2.3 Fundamental metafunction building block
There are two ubiquitous idioms for type traits:
- define a public data member value with a given value
- define a public member typedef type that names a given type
It is surprising that there is a standard utility providing the former (
std::integral_constant
), but no standard utility providing the latter.type_identity
is this utility. It is a fundamental building block that other metafunctions can simply inherit from. For example,remove_const
could be implemented as follows:template <typename T> struct remove_const : type_identity<T> {}; template <typename T> struct remove_const<T const> : type_identity<T> {};
Its implementation is simple:
template<class T>
struct type_identity
{
using type = T;
};
So, I try to use type_identity
widely in my codes, including personal implementation of Detection Idiom:
namespace detail
{
template<class Default,
class AlwaysVoid,
template<class...>
class Op,
class... Args>
struct detector : type_identity<Default> // here
{
using value_t = std::false_type;
};
template<class Default, template<class...> class Op, class... Args>
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...>
: type_identity<Op<Args...>> // here
{
using value_t = std::true_type;
};
} // namespace detail
// ......
It works fine everywhere until I used libcxx's testsuits for my own implementation of is_destructible
, below is the failure case:
struct ProtectedDestructor
{
protected:
~ProtectedDestructor()
{}
};
// ......
template<class T>
void
test_is_not_destructible()
{
static_assert(!is_destructible<T>::value, "");
// ......
}
// ......
test_is_not_destructible<ProtectedDestructor>();
prog.cc:83:47: error: '~ProtectedDestructor' is a protected member of 'ProtectedDestructor'
using has_dtor = decltype(std::declval().~U()); ^ prog.cc:26:19: note: in instantiation of template type alias 'has_dtor' requested here
: type_identity<Op<Args...>> ^
prog.cc:45:1: note: in instantiation of template class 'detail::detector
......
It's werid that once replace type_identity
with trival using type = ......
, the compiler has no error, demo. For other trival has_member
check, type_identity
works fine, demo.
So, the only problem here is, for protected dtor, type_identity
will force struct detail::detector
to check the validity of dtor, while using type = something
will not.
I think the solution is simple, just remove type_identity
, and use using type = something
directly, just like Walter E. Brown's original implementation. But the question is:
why does type_idintity
break here, while trival using type = something
not?