Type_traits: is_convertible and std::pair problem

The type_traits library gives me somewhat erroneous answers when dealing with pairs of pairs. The following code produces the errors below, but interestingly, the BOOST_ASSERT actually succeeds. It seems is_convertible thinks a pair<pair<int, int>, int> is convertible to a plain old pair<int, int>, but the compiler (and this coder) takes a different view... #include <utility> #include <boost/assert.hpp> #include <boost/type_traits/is_convertible.hpp> std::pair<int, int> go(std::pair<int, int> p) { return p; } int main() { BOOST_STATIC_ASSERT(( boost::is_convertible< std::pair< std::pair<int, int>, int >, std::pair<int, int> >::value )); std::pair<std::pair<int, int>, int> p1 = std::make_pair(std::make_pair(1,2),3); std::pair<int, int> p2 = go(p1); return 0; } $ g++-4.1.1 test.cpp -I/usr/include/boost-1_33_1 /home/vsekhar/gcc-4.1.1/lib/gcc/i686-pc-cygwin/4.1.1/../../../../include/c++/4.1.1/bits/stl_pair.h: In constructor 'std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U1 = std::pair<int, int>, _U2 = int, _T1 = int, _T2 = int]': test.cpp:25: instantiated from here /home/vsekhar/gcc-4.1.1/lib/gcc/i686-pc-cygwin/4.1.1/../../../../include/c++/4.1.1/bits/stl_pair.h:90: error: cannot convert 'const std::pair<int, int>' to 'int' in initialization The compiler appears to be attempting a piecewise conversion of the contents of the pair, hence the error about converting pair<int, int> to 'int' rather than an error about converting pair<pair<int, int>, int> to pair<int, int>. Is there a method of converting that is_convertible has in mind when it returns true for the aforementioned conversion? I'm testing here for simple implicit conversion... -v

AMDG cp now wrote:
The type_traits library gives me somewhat erroneous answers when dealing with pairs of pairs.
The following code produces the errors below, but interestingly, the BOOST_ASSERT actually succeeds. It seems is_convertible thinks a pair<pair<int, int>, int> is convertible to a plain old pair<int, int>, but the compiler (and this coder) takes a different view...
It's impossible to make it work in the general case. boost::is_convertible only checks whether there is a non-explicit constructor. To make the check work, we would need to somehow instantiate the constructor and detect whether compiling it succeeded of not. There is no way to do this in C++. Not possible: template<class T, class U> struct is_convertible_impl { static_try { U u = T(); typedef true_type type; } catch(compilation_error&) { typedef false_type type; } } In Christ, Steven Watanabe

cp now wrote:
The type_traits library gives me somewhat erroneous answers when dealing with pairs of pairs.
The compiler appears to be attempting a piecewise conversion of the contents of the pair, hence the error about converting pair<int, int> to 'int' rather than an error about converting pair<pair<int, int>, int> to pair<int, int>.
Is there a method of converting that is_convertible has in mind when it returns true for the aforementioned conversion? I'm testing here for simple implicit conversion...
is_convertible does tell you about implicit convertibility, it answers the question: Does type "To" have a copy constructor that accepts a type "From"? And indeed std::pair has such a constructor, so is_convertible answers true. Unfortunately what no traits class can answer is the question: Does this code compile? And that's where this example fails: std::pair has a "catch all" constructor that will accept any kind of pair as an argument, so that is_convertible<pair1_type, pair2_type>::value must always be true, even though the code may fail to compile inside the constructor :-( However... given that pairs (and in the future tuples) are part of the standard, it may be worth while fixing is_convertible for this special case. Interestingly, had std::pair's constructor been defined in terms of enable_if and is_convertible, it could have been defined in such a way that it's signature was only valid if the code would compile: and is_convertible would then have "just plain worked" for pairs. No doubt C++0x's concepts can achieve something similar. Hope this explanation helps, John.

On Jan 29, 2008 11:03 PM, John Maddock <john@johnmaddock.co.uk> wrote:
cp now wrote:
The type_traits library gives me somewhat erroneous answers when dealing with pairs of pairs.
The compiler appears to be attempting a piecewise conversion of the contents of the pair, hence the error about converting pair<int, int> to 'int' rather than an error about converting pair<pair<int, int>, int> to pair<int, int>.
Is there a method of converting that is_convertible has in mind when it returns true for the aforementioned conversion? I'm testing here for simple implicit conversion...
is_convertible does tell you about implicit convertibility, it answers the question:
Does type "To" have a copy constructor that accepts a type "From"?
And indeed std::pair has such a constructor, so is_convertible answers true.
Unfortunately what no traits class can answer is the question:
Does this code compile?
And that's where this example fails: std::pair has a "catch all" constructor that will accept any kind of pair as an argument, so that is_convertible<pair1_type, pair2_type>::value must always be true, even though the code may fail to compile inside the constructor :-(
However... given that pairs (and in the future tuples) are part of the standard, it may be worth while fixing is_convertible for this special case.
Interestingly, had std::pair's constructor been defined in terms of enable_if and is_convertible, it could have been defined in such a way that it's signature was only valid if the code would compile: and is_convertible would then have "just plain worked" for pairs. No doubt C++0x's concepts can achieve something similar.
Hope this explanation helps, John.
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Makes sense. Any quick patch possible for is_convertible? I'm thinking if TO and FROM are either both pairs or both tuples (of the same size) then is_convertible is just recursively applied to each contained type. I tried to decipher the header file but it's a little beyond my abilities. Probably could also eventually be extended to any multi-type container like spirit containers?
participants (3)
-
cp now
-
John Maddock
-
Steven Watanabe