Search code examples
c++standardslanguage-designc++17type-traits

Is there a typical use case that must use `is_detected_v`?


Below is excerpted from cppref:

#include <experimental/type_traits>

template<class T>
using copy_assign_t = decltype(std::declval<T&>() = std::declval<const T&>());

struct Meow { };

using namespace std::experimental;

int main()
{
    static_assert(is_detected_v<copy_assign_t, Meow>,
        "Meow should be copy assignable!"); // version 1

    static_assert(is_copy_assignable_v<Meow>,
        "Meow should be copy assignable!"); // version 2
}

Is there any difference between version 1 and version 2?

Is there a typical use case that must use is_detected_v?


Solution

  • std::is_detected can be used as a building block for std::is_copy_assignable. If you want to check for copy-assignability, you should use std::is_copy_assignable. If you need to check for the existence of a custom operation/member function, std::is_detected gives you an easy way of doing that.

    template<class T>
    using foo_detector = decltype(std::declval<T&>().foo());
    
    static_assert(!is_detected_v<foo_detector, Meow>, "Meow shouldn't have `.foo()`!");
    

    A realistic example use case is unification of different APIs:

    template<class T>
    using clean_detector = decltype(std::declval<T&>().clean());
    
    template<class T>
    using clear_detector = decltype(std::declval<T&>().clear());
    
    template <typename T>
    auto clear(const T& x) -> std::enable_if_t<is_detected_v<has_clean, T>>
    {
        x.clean();
    }
    
    template <typename T>
    auto clear(const T& x) -> std::enable_if_t<is_detected_v<has_clear, T>>
    {
        x.clear();
    }
    

    Usage example:

    struct Foo { void clean(); };
    struct Bar { void clear(); };
    
    int main()
    {
        Foo f; Bar b;
        clear(f);
        clear(b);
    }