https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71899
--- Comment #1 from Daniel Krügler <daniel.kruegler at googlemail dot com> --- I have now a working implementation available, my minimum requirement set is summarized by the following trait definition: //-------------------------------- // Utility to detect BooleanTestable types (NB: LWG 2114). template<typename _Tp, bool = __is_referenceable<_Tp>::value> struct __is_boolean_testable_impl; template<typename _Tp> struct __is_boolean_testable_impl<_Tp, false> : public false_type { }; template<typename _Tp> struct __is_boolean_testable_impl<_Tp, true> : public __and_<is_convertible<const _Tp&, bool>, is_constructible<bool, const _Tp&>> { }; template<typename _Tp> struct __is_boolean_testable : public __is_boolean_testable_impl<_Tp> { }; //-------------------------------- During my work on this I wanted to stretch its limits and extended the definition to cover basically all statically testable expressions as currently specified by the BooleanTestable requirements [booleantestable] in LWG 2743 as follows: //-------------------------------- // Utility to detect BooleanTestable types (NB: LWG 2114). template<typename _Tp, bool = __is_referenceable<_Tp>::value> struct __is_boolean_testable_impl; template<typename _Tp> struct __is_boolean_testable_impl<_Tp, false> : public false_type { }; #ifdef EXT_BOOLEAN_TESTABLE_OPS struct __do_is_boolean_testable_ext_impl { struct __bt { operator bool() const; }; template<typename _Tp, typename _Rt0 = decltype(!declval<_Tp>()), typename _Rt1 = decltype(declval<_Tp>() && declval<const __bt&>()), typename _Rt2 = decltype(declval<_Tp>() || declval<const __bt&>()), typename _Rt3 = decltype(declval<const __bt&>() && declval<_Tp>()), typename _Rt4 = decltype(declval<const __bt&>() || declval<_Tp>()), typename _Rt5 = decltype(declval<_Tp>() && declval<_Tp>()), typename _Rt6 = decltype(declval<_Tp>() || declval<_Tp>()), typename = typename enable_if<__and_< is_same<_Rt0, bool>, is_same<_Rt1, bool>, is_same<_Rt2, bool>, is_same<_Rt3, bool>, is_same<_Rt4, bool>, is_same<_Rt5, bool>, is_same<_Rt6, bool> >::value>::type> static true_type __test(int); template<typename> static false_type __test(...); }; template<typename _Tp> struct __is_boolean_testable_ext : public __do_is_boolean_testable_ext_impl { typedef decltype(__test<_Tp>(0)) type; }; template<typename _Tp> struct __is_boolean_testable_ext_safe : public __is_boolean_testable_ext<_Tp>::type { }; #endif template<typename _Tp> struct __is_boolean_testable_impl<_Tp, true> : public __and_<is_convertible<const _Tp&, bool>, is_constructible<bool, const _Tp&> #ifdef EXT_BOOLEAN_TESTABLE_OPS , __is_boolean_testable_ext_safe<const _Tp&> #endif > { }; template<typename _Tp> struct __is_boolean_testable : public __is_boolean_testable_impl<_Tp> { }; //-------------------------------- Please note that the extended test added the slightly stricter requirement is_same<_Rt0, bool> instead of __is_boolean_testable<_Rt0>, because the latter would have lead to an indefinite recursion. But even this much stricter (and more complex) __is_boolean_testable definition (i.e. with EXT_BOOLEAN_TESTABLE_OPS being defined as shown above) resulted in an accepted test case: //--------------------------------- #include <type_traits> #include <bitset> #include <vector> struct BooleanLike { operator bool() const; }; struct NotBooleanLike1 { explicit operator bool() const; }; struct NotBooleanLike2 { using Bool = int; explicit operator bool() const = delete; operator Bool() const; }; struct NotBooleanLike3 { operator bool(); }; void test01() { using std::__is_boolean_testable; // Positive tests. static_assert(__is_boolean_testable<bool>::value, ""); static_assert(__is_boolean_testable<bool&>::value, ""); static_assert(__is_boolean_testable<const bool&>::value, ""); static_assert(__is_boolean_testable<std::true_type>::value, ""); static_assert(__is_boolean_testable<std::false_type>::value, ""); static_assert(__is_boolean_testable<BooleanLike>::value, ""); static_assert(__is_boolean_testable<std::bitset<1>::reference>::value, ""); static_assert(__is_boolean_testable<std::bitset<24>::reference>::value, ""); static_assert(__is_boolean_testable<std::vector<bool>::reference>::value, ""); // Negative tests. static_assert(!__is_boolean_testable<void>::value, ""); static_assert(!__is_boolean_testable<NotBooleanLike1>::value, ""); static_assert(!__is_boolean_testable<NotBooleanLike2>::value, ""); static_assert(!__is_boolean_testable<NotBooleanLike3>::value, ""); } //--------------------------------- I would therefore like to ask which form of the trait would be considered more welcome as internal utility for libstdc++?