Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2006-05-08 13:44:03


Tobias Schwinger <tschwinger_at_[hidden]> writes:

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

>

> 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.

And begin can be spoofed, too, can't it? Okay, it's very unlikely.

> 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).

Exactly.

>>>>>

>>>>>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...

I am not thinking about this problem freshly today; all I remember is

that it's a morasse with no good answers. But I could be wrong. If

you can supply a patch that works, and you can demonstrate it with

convincing tests, I'll be happy to recommend that Aleksey commit it.

>>>>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...

Yes but it *totally* begs the question. Because, what do you have to

know in order to decide whether begin<x> should return void_? That's

right, you have to know whether x is a sequence.

>>>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?

foo<is_sequence<int(int,long)>::value>::bar() calls one function in TU

#1 and another function in TU #2. Clear yet?

> 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' ;-)

Show me the money. Err, the code.

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk