
On Wed, Aug 8, 2012 at 8:59 PM, John Bytheway <jbytheway+boost@gmail.com>wrote:
I have been tracking down an issue with some of my code which compiles fine with gcc but not clang. It manifested as a failure in Boost.Parameter but I eventually pinned it down to an inconsistency in the behaviour of boost::is_convertible. The following program demonstrates the issue:
============== #include <boost/type_traits/is_convertible.hpp> #include <boost/static_assert.hpp>
class A {};
int main() { BOOST_STATIC_ASSERT((boost::is_convertible<A, A&>::value)); } ==============
This compiles fine under g++ (4.7.1), but the assertion fires under clang++ (r160940).
I would consider clang correct and gcc incorrect (this is without consulting the documentation).
This is not too surprising because is_convertible is implemented in completely different ways on the two compilers:
- on clang it is in terms of the __is_convertible intrinsic, which behaves like std::is_convertible and fails because rvalue references don't convert to lvalue references.
- on gcc it has a complex custom implementation which at some point performs add_reference<> on the first argument and thus determines that the conversion is OK.
That appears to explain it; again, I would consider the add_reference incorrect and a limitation. If one wants to add a reference qualifier (when using what I consider a correct implementation of is_convertible), one may do so explicitly; but, in the case of gcc's implementation, one can't prevent the addition of reference qualifiers, so there's no way to test convertibility from rvalues. Reading the docs for boost::is_convertible I think the clang
interpretation is closer to the intention, in which case the gcc implementation is wrong, and so is Boost.Parameter (which relies on this behaviour).
On the other hand, I suspect there's probably other code out there that depends on this in a similar way to Boost.Parameter,
Well, *technically*, such other code would be depending on an *implementation*, let's say, "feature", that is, according to your reading, undocumented. so perhaps it would
be safer to tweak the clang implementation instead, and deviate from std::is_convertible.
Other code aside, I believe the correct thing to do would be to put the gcc implementation more in line with the clang, std, and Boost-documented behavior. Maybe make the change to the gcc implementation and see what fails within Boost first? Any thoughts?
I guess so :) - Jeff