
On 2017-08-17 11:33, Gavin Lambert via Boost wrote:
On 17/08/2017 12:45, Vladimir Batov wrote:
Thanks, Gavin. Is it how it is done these days? Nice. Incorporated. Many thanks... clang still fails... now I am starting to look suspiciously in clang's direction.
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.
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.