
There is something seemingly basic that puzzles me greatly. I am hoping people might clarify something I totally fail to understand. I've been using BOOST_STATIC_CONSTANT for ages (with GCC). Now I have something seemingly non-controversial: template<typename user_type> struct impl_ptr { using yes_type = boost::type_traits::yes_type; using no_type = boost::type_traits::no_type; using ptr_type = typename std::remove_const<user_type>::type*; template<typename Y> static yes_type test (Y*, typename Y::impl_ptr_type* =nullptr); static no_type test (...); BOOST_STATIC_CONSTANT(bool, value = (1 == sizeof(test(ptr_type(nullptr))))); }; When compiled with gcc-.5.4.0, both lines below pass: BOOST_TEST(true == boost::impl_ptr<Shared>::value); BOOST_TEST(true == boost::impl_ptr<Shared const>::value); The only difference between them is "const". However, when I compile with clang-4.0, the second (const) line passes. However, the first one fails! I refuse to believe it's a clang glitch. It must be me doing something really stupid. Help?!

On 17/08/2017 11:22, Vladimir Batov wrote:
I can't answer this specific question, but since you're targeting C++11 anyway, shouldn't you be using std:: type traits? So, something like: template <typename T> class has_impl_ptr_type { template <typename T1> static typename T1::impl_ptr_type test(int); template <typename> static void test(...); public: enum { value = !std::is_void<decltype(test<T>(0))>::value }; };

On 17/08/2017 12:45, Vladimir Batov wrote:
FYI, the complete program: #include <type_traits> template <typename T> class has_impl_ptr_type { template <typename T1> static typename T1::impl_ptr_type test(int); template <typename> static void test(...); public: enum { value = !std::is_void<decltype(test<T>(0))>::value }; }; struct A { }; struct B { typedef int impl_ptr_type; }; static_assert(!has_impl_ptr_type<A>::value, ""); static_assert( has_impl_ptr_type<B>::value, ""); static_assert( has_impl_ptr_type<B const>::value, ""); int main() { return 0; } Compiles successfully for me with -std=c++11 on gcc 5.4.0 and clang 3.8.0, as well as VS2015. So unless this is some kind of regression in clang-4, your problem probably lies elsewhere.

On 2017-08-17 11:33, Gavin Lambert via Boost wrote:
Indeed, when has_impl_ptr_type is a separate class, it works as you tested. What I initially had was that test was/is part of impl_ptr template <typename T> struct impl_ptr { ... enum { value = !std::is_void<decltype(test<T>(0))>::value }; } ... and T was declared as struct T : impl_ptr<T>::shared { ... }; That is, it appears, when the compiler gets to look at impl_ptr<T>, it has T incomplete!.. and fails is such a weird way. I think to reproduce that in your code, it'll have to be template <typename T> class has_impl_ptr_type { ... struct base; }; template <typename T> struct has_impl_ptr_type::base { using impl_ptr_type = base; }; struct B : has_impl_ptr_type<B>::base { ... }; static_assert( has_impl_ptr_type<B>::value, ""); I suspect he above to fail with clang. So, I am untangling this knot as you described above. Many thanks.

On Wed, Aug 16, 2017 at 7:22 PM, Vladimir Batov wrote:
This is to detect a member 'impl_ptr_type' type? Just: template<class, class = void> struct has_impl_ptr_type : boost::false_type { }; template<class T> struct has_impl_ptr_type<T, boost::void_t<typename T::impl_ptr_type> > : boost::true_type { }; Glen

Boost - Dev mailing list wrote
This only requires C++11; it doesn't work on earlier versions of MSVC because MSVC was (and still is) lagging behind on support for expression-SFINAE. -- View this message in context: http://boost.2283326.n4.nabble.com/BOOST-STATIC-CONSTANT-tp4698066p4698086.h... Sent from the Boost - Dev mailing list archive at Nabble.com.

On 17/08/2017 16:35, dodheim wrote:
std::void_t does not exist until C++17. However the VS2015 STL adds it anyway. boost::void_t does not exist until 1.64. However it only works on compilers that support expression-SFINAE (which is most C++11 compilers except VS, until VS2015). This is what I meant by the above.

On 08/17/17 08:33, Gavin Lambert via Boost wrote:
Boost.Core has had enable_if_has_type for this purpose for a long time. By itself, neither void_t nor enable_if_has_type requires expression SFINAE. It will only require one in some uses, typically involving decltype, when you test if an expression is valid (i.e. has a type). It works with as far as C++03 with regard to testing for nested types.
participants (6)
-
Andrey Semashev
-
dodheim
-
Edward Diener
-
Gavin Lambert
-
Glen Fernandes
-
Vladimir Batov