
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:
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?!
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 2017-08-17 10:19, Gavin Lambert via Boost wrote:
On 17/08/2017 11:22, Vladimir Batov wrote:
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?!
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 }; };
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.

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.

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.

On Wed, Aug 16, 2017 at 7:22 PM, Vladimir Batov wrote:
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?!
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

On 17/08/2017 13:27, Glen Fernandes 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 { };
That *is* a nicer way to do it. Requires a minimum of Boost 1.64 or C++17, though. (Or VS2015, apparently.)

On 2017-08-17 11:45, Gavin Lambert via Boost wrote:
On 17/08/2017 13:27, Glen Fernandes 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 { };
That *is* a nicer way to do it. Requires a minimum of Boost 1.64 or C++17, though. (Or VS2015, apparently.)
Yes, I liked it too. :-) Thanks, Glen.

On Wed, Aug 16, 2017 at 9:45 PM, Gavin Lambert via Boost wrote:
On 17/08/2017 13:27, Glen Fernandes 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 { };
That *is* a nicer way to do it. Requires a minimum of Boost 1.64 or C++17, though. (Or VS2015, apparently.)
*Nod* - since Vladimir's intent is proposing this library for Boost, I just assume that his library can assume Boost v.Latest. :) Glen

On 2017-08-17 12:14, Glen Fernandes via Boost wrote:
On Wed, Aug 16, 2017 at 9:45 PM, Gavin Lambert via Boost wrote:
On 17/08/2017 13:27, Glen Fernandes 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 { };
That *is* a nicer way to do it. Requires a minimum of Boost 1.64 or C++17, though. (Or VS2015, apparently.)
*Nod* - since Vladimir's intent is proposing this library for Boost, I just assume that his library can assume Boost v.Latest. :)
Thank again, Glen. I've incorporated your version. As a separate struct (as you and Gavin showed) all works now. Many thanks.

Boost - Dev mailing list wrote
On 17/08/2017 13:27, Glen Fernandes 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 { };
That *is* a nicer way to do it. Requires a minimum of Boost 1.64 or C++17, though. (Or VS2015, apparently.)
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:
Boost - Dev mailing list wrote
On 17/08/2017 13:27, Glen Fernandes 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 { };
That *is* a nicer way to do it. Requires a minimum of Boost 1.64 or C++17, though. (Or VS2015, apparently.)
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.
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:
On 17/08/2017 16:35, dodheim wrote:
Boost - Dev mailing list wrote
On 17/08/2017 13:27, Glen Fernandes 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 { };
That *is* a nicer way to do it. Requires a minimum of Boost 1.64 or C++17, though. (Or VS2015, apparently.)
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.
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).
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.

On 8/16/2017 7:22 PM, Vladimir Batov via Boost wrote:
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?!
Can you not use tti to do what you want to do ?

On 2017-08-17 12:26, Edward Diener via Boost wrote:
On 8/16/2017 7:22 PM, Vladimir Batov via Boost wrote:
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?!
Can you not use tti to do what you want to do ?
Thanks, Ed. The code above was there for god-knows-how-long. I am reading TTI docs now to make sure to use it in the future. Tnx.
participants (6)
-
Andrey Semashev
-
dodheim
-
Edward Diener
-
Gavin Lambert
-
Glen Fernandes
-
Vladimir Batov