Boost logo

Boost :

From: Tobias Schwinger (tschwinger_at_[hidden])
Date: 2006-05-08 13:21:31

I went through the code just yesterday, so...

David Abrahams wrote:
> Joel de Guzman <joel_at_[hidden]> writes:
>>David Abrahams wrote:
>>>Joel de Guzman <joel_at_[hidden]> writes:
>>>>David Abrahams wrote:
>>>>>Tobias Schwinger <tschwinger_at_[hidden]> writes:
>>>>>>Why not make is_sequence work reliably?
>>>>>Because it's impossible. It's always going to look for some features
>>>>>of the type being tested that can be present even if the type is not,
>>>>>in fact, a sequence.

The guessing stuff directly in 'is_sequence' is a workaround for broken compilers. For proper compilers:

  is_sequence<T> <=> is_same< begin<T>, void_ >

. So 'is_sequence' works perfectly well and can also work perfectly reliable given that 'begin' does; 'begin', however, fails to compile if there is a 'tag' member for a non-sequence type instead of returning 'void_' which would be the documented behaviour.

The reason is "guessing mess" in 'begin_impl': the primary template attempts to return 'T::begin' (it seems to be a convenience feature so a sequence implementor can simply specify a type member called 'begin' and does not need to specialize 'begin_impl'). 'sequence_tag' is assumed to sort out non-sequences -- but it is impossible without guessing (or adding to the user's responsibilities when registering non-sequence types for tag dispatch).

>>>>I don't see why it is impossible. MPL sequences can always
>>>>specialize is_sequence<T>. is_sequence *can* work reliably
>>>>100% of the time:
>>>> template <class S>
>>>> struct is_sequence : mpl::false_ {}; // default
>>>> // your specializations here

That should not even be needed -- implementing 'begin' should be enough...

>>>The problem isn't false negatives, it's false positives. In practice
>>>you can probably make it vanishingly unlikely that some random
>>>third-party type will pass all the default is_sequence tests, but you
>>>can never make it 100% impossible as long as:
>>> a. sequences can be arbitrary types, such as void(int,long,char)
>>> b. is_sequence<S> reporting correctly is not part of the sequence
>>> requirements

c. begin works properly

'begin<non_sequence>::type' being 'void_' (maybe more importantly that it compiles) is already part of the requirements...

>>I believe that the default is_sequence should strictly be
>>mpl::false_: no guessing games.
>>I think:
>>a) if you want to make specific types (e.g. RT(A0,A1,...AN)),
>>a sequence, then specialize is_sequence for those.
> ODR violations ensue. int(int,long) is a sequence in one TU but not
> in another.

Just curious: all these classes should have internal linkage - am I missing something?

>>Sure you can do it for only a limited number of args, but, hey, so
>>do other libraries that provide traits over function types/ member
>>function pointer types, function pointers. Are there other
>>arbitrary types you have in mind that can be sequences? If there
>>are, specialize for them. Explicit is better than implicit, right? I
>>think the guessing game where MPL is trying some heuristics as to
>>how an MPL sequence looks like (e.g. it has a tag typedef, etc), is
>>what's causing us problems. I think it is the wrong approach.
>>b) If is_sequence is part of MPL's public interface, then it
>>should give reliable results. If that requires b, then so be it.
> Right. Which is why I encouraged Aleksey to remove it. I'm surprised
> it's even documented in the reference manual.

The dispatcher for sequence operations won't become any better from removing 'is_sequence' (surprise guaranteed ;P )...

So here's my €0,02-plan:

-- require 'begin_impl' to be specialized; IOW drop that "type member convenience
   stuff" (described above) -- it is what makes the dispatch a mess!
-- throw out 'sequence_tag' (it doesn't work, can't work and isn't needed)
-- keep 'is_sequence' ;-)



Boost list run by bdawes at, gregod at, cpdaniel at, john at