По этой теме много сопутствующих вопросов, но меня до сих пор озадачивает следующий случай:
#include <iostream>
#include <utility>
struct A {};
struct B { void operator + (const B& /* other */) {} };
struct C { C operator + (const C& /* other */) {return *this;} };
struct D { D& operator + (const D& /* other */) {return *this;} };
template <typename T, typename = void>
struct has_p_op : std::false_type {};
template <typename T>
struct has_p_op<T, decltype(std::declval<T>() + std::declval<T>())> : std::true_type {};
int main()
{
constexpr bool a = has_p_op<A>::value; // false
constexpr bool b = has_p_op<B>::value; // true
constexpr bool c = has_p_op<C>::value; // false
constexpr bool d = has_p_op<D>::value; // false
std::cout << a << b << c << d << std::endl;
}
почему c и d не оба true?
Собирался написать «но я попробовал decltype(std::declval<T>() + std::declval<T>(), void), и это не сработало», а теперь вижу, что пропустил скобку в void()





Возврат типа void отсутствовал.
v1:
template <typename T>
struct has_p_op<T, decltype(std::declval<T>() + std::declval<T>(), void())> : std::true_type {};
версия 2:
template <typename T>
struct has_p_op<T, std::void_t<decltype(std::declval<T>() + std::declval<T>())>> : std::true_type {};
Потому что возвращаемый тип выражения не
void? Именно поэтому у нас естьstd::void_t.