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
?
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);
}