
Tim Robertson <timr@u.washington.edu> writes:
On Sep 6, 2006, at 12:19 AM, David Abrahams wrote:
But that's probably not what you meant for it to do. In this case it looks like you have a kind of circular dependency problem. You can actually learn a lot by reading the error messages. Reversing your instantiation backtrace, I get:
test.cpp:36: instantiated from here
I assume that's the 2nd line of main()
test.cpp:36: instantiated from `boost::enable_if<boost::is_convertible<Foo, Foo>, void>'
It's trying to decide if the first ctor is a match
test.cpp:36: instantiated from `boost::is_convertible<Foo, Foo>'
Yes, everything up to this point was straightforward. The compiler is trying to choose between the constructors by instantiating the various enable_if templates. Unfortunately, I'm not as familiar with the internals of enable_if<> as many of you, and the *next* part was a bit confusing...
To do that it needs to decide the value nested in is_convertible<Foo,Foo>.
Note---^^^^^^^^^^^^^^^^^^^^^^^
test.cpp:36: instantiated from `boost::detail::is_convertible_impl_dispatch<Foo, Foo>' /boost/boost/type_traits/is_convertible.hpp:228: instantiated from `boost::detail::is_convertible_impl<Foo, Foo>' /boost/boost/type_traits/is_convertible.hpp:128: instantiated from `boost::detail::is_convertible_basic_impl<Foo&, Foo>'
Inside implementation details of is_convertible:
/boost/boost/type_traits/is_convertible.hpp: In instantiation of `boost::disable_if<boost::is_convertible<Foo, Foo>, void>':
To determine convertibility it has to check out the ctors and see if there's one that implicitly converts Foo->Foo
...but it can't do that if the constructors that would perform the conversion are themselves enabled/disabled with enable_if?
Almost but, not quite. It's the specific criterion on whose basis they're enabled/disabled: is Foo convertible to Foo? The problem is that is_convertible<Foo,Foo>::value is not yet known, and (aside from the fact that there's an implicitly generated copy ctor that's a perfect match which the compiler seems to ignore at this stage, of course) without that ::value the compiler can't decide whether either of those constructors is a match for a Foo argument. In fact, we're only checking for that match because we want to know that very ::value!
/boost/boost/type_traits/is_convertible.hpp:128: error: `value' is not a member of type `boost::is_convertible<Foo, Foo>'
In evaluating the applicability of the first ctor, it needs to know the value nested in is_convertible<Foo,Foo>. We've been here before!
Right. So again, it seems as though it isn't possible to do what I'm trying to do.
Sure it is. You could use enable_if< mpl::or_<is_same<T,Foo>, is_convertible<T,Foo> >, ... > Type sameness can be determined without looking at constructors or even knowing anything about the definition of the type.
The enable_if<> template requires the use of the class' copy constructor. Even if a default copy constructor is provided, the compiler still wants to obtain the nested value type in is_convertible<>, and it can't do that, because it needs to decide between the three copy-constructor-like functions in the class, two of which depend on enable_if<> to determine their signatures. Is that the correct way to interpret this situation?
Sorta. -- Dave Abrahams Boost Consulting www.boost-consulting.com