
On 28 Jun 2017, at 00:53, dariomt@gmail.com wrote:
2017-06-27 17:46 GMT+02:00 d25fe0be@outlook.com <d25fe0be@outlook.com>: So I suspect this is a bug in 'type_traits' library, but I'm not sure. Hopefully somebody else can confirm. (I'm sorry but I don't know to whom should I CC this post.)
I don't know why clang accepts your code though. Perhaps `boost::is_convertible` is conditionally compiled to some different implementations in Clang.
Thanks for the analysis. My guess is that clang uses a different implementation of is_convertible. Also, I guess this works in C++14 because std::is_convertible is used instead?
Yes, after a deeper dig, `boost/type_traits/intrinsics.hpp` shows that `type_traits` uses Clang's intrinsics to do the job: ``` 157 #if defined(BOOST_CLANG) && defined(__has_feature) && !defined(__CUDACC__) [...] 213 # if __has_feature(is_convertible_to) 214 # define BOOST_IS_CONVERTIBLE(T,U) __is_convertible_to(T,U) 215 # endif ``` After commenting out macro `BOOST_IS_CONVERTIBLE`, clang errors out the original code as well. And I believe this finding gives us an easier workaround: Just defining our own `BOOST_IS_CONVERTIBLE` before including `boost/variant.hpp`, and the compilation error should disappear. ``` #include <type_traits> #define BOOST_IS_CONVERTIBLE(T,U) std::is_convertible<T, U>::value #include <boost/variant.hpp> [...] ``` As for the implementation of `boost::is_convertible` in C++14, although I agree with you that `type_traits` could (or should have?) use std::is_convertible when available, `boost/type_traits/is_convertible.hpp` shows that `type_traits` implemented their own C++11 version: ``` 53 // 54 55 namespace detail { 56 57 #if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !(defined(BOOST_GCC) && (BOOST_GCC < 40700)) 58 59 // This is a C++11 conforming version, place this first and use it wherever possible: 60 61 # define BOOST_TT_CXX11_IS_CONVERTIBLE 62 63 template <class A, class B, class C> 64 struct or_helper 65 { 66 static const bool value = (A::value || B::value || C::value); 67 }; 68 69 template<typename From, typename To, bool b = or_helper<boost::is_void<From>, boost::is_function<To>, boost::is_array<To> >::value> 70 struct is_convertible_basic_impl 71 { 72 // Nothing converts to function or array, but void converts to void: 73 static const bool value = is_void<To>::value; 74 }; 75 76 template<typename From, typename To> 77 class is_convertible_basic_impl<From, To, false> 78 { 79 typedef char one; ```