why does type_identity break the implementation of is_detected

476 Views Asked by At

p0887r1:

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>();

live demo:

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?

0

There are 0 best solutions below