[Bug libstdc++/71899] An internal BooleanTestable trait should be provided
daniel.kruegler at googlemail dot com
gcc-bugzilla@gcc.gnu.org
Sat Jul 16 16:39:00 GMT 2016
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++?
More information about the Gcc-bugs
mailing list