Проблема с вашим logical_value
заключается в том, что вы не предлагаете компилятору альтернативный путь в случае возникновения ошибки подстановки.
Я делаю так:
#include <utility>
#include <array>
template<typename T, typename U>
constexpr auto check_addition(int) -> decltype(std::declval<T>() + std::declval<U>() , std::true_type{});
template<typename T, typename U>
constexpr std::false_type check_addition(...);
template<typename T, typename U>
constexpr bool can_add = decltype(check_addition<T, U>(0))::value;
int main() {
static_assert(can_add<int, float>);
static_assert(!can_add<std::string, float>);
}
Идея состоит в том, чтобы использовать две перегрузки, одну с определенным аргументом типа (int
в моем случае), а другую с многоточием,Когда мы вызываем эту перегруженную функцию с параметром int
, компилятор сначала проверяет перегрузку int
, где он должен выполнить требуемую проверку.
Оператор запятой используется для предоставления true_type
кактип возвращаемого значения в приведенной проверке завершается успешно.
Если первая перегрузка SFINAE завершается неудачно, выбирается вторая перегрузка, которая всегда возвращает false_type
.