我的 SFINAE 出了什么问题?:测试支持的运算符
What's wrong with my SFINAE?: Testing Supported Operators
这是有问题的代码:
template <typename=std::enable_if_t<supports_v<std::equal_to<>, T>> >
bool alreadyValue(const T &value) { return this->value == value; }
// alternate case if T does not support equals operator
bool alreadyValue(const T &value) { return false; }
这是我的支持定义:
template<typename F, typename... T, typename = decltype(std::declval<F>()(std::declval<T>()...))>
std::true_type supports_test(const F&, const T&...);
std::false_type supports_test(...);
template<typename> struct supports;
template<typename F, typename... T> struct supports<F(T...)>
: decltype(supports_test(std::declval<F>(), std::declval<T>()...)){};
template<typename F, typename T>
constexpr bool supports_v = supports<F(T, T)>::value;
template<typename F, typename... T>
constexpr bool all_supports_v = (supports<F(T, T)>::value && ...);
现在,MSVC 19.20 已经没有问题了。
但是 GCC 9.1 抱怨说:
In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = supports_v<std::equal_to<void>, A>; _Tp = void]':
error: no type named 'type' in 'struct std::enable_if<false, void>'
既然 SFINAE 知道“no type in struct”应该无声地失败,因为它不是错误,我的问题是我做错了什么吗?
这是我正在使用的示例:
- (海湾合作委员会 9.1)https://godbolt.org/z/LNfjyp
- (MSVC 19.20)https://godbolt.org/z/wJqXFq
正如 stated and 所暗示的那样,enable_if 不在未计算的上下文中,因为没有依赖于该函数的泛型类型。所以没有SFINAE。
作为解决方案,我改为将函数构建为通用支持函数:
template<typename T, bool=supports_v<std::equal_to<>, T>>
struct is_equal_t;
template<typename T>
struct is_equal_t<T, true> {
bool operator() (const T& x, const T& y) const { return x==y; }
};
template<typename T>
struct is_equal_t<T, false> {
bool operator() (const T& x, const T& y) const { return false; }
};
template<typename T>
bool is_equal(const T& x, const T& y) {
static is_equal_t<T> cmp;
return cmp(x, y);
}
这是有问题的代码:
template <typename=std::enable_if_t<supports_v<std::equal_to<>, T>> >
bool alreadyValue(const T &value) { return this->value == value; }
// alternate case if T does not support equals operator
bool alreadyValue(const T &value) { return false; }
这是我的支持定义:
template<typename F, typename... T, typename = decltype(std::declval<F>()(std::declval<T>()...))>
std::true_type supports_test(const F&, const T&...);
std::false_type supports_test(...);
template<typename> struct supports;
template<typename F, typename... T> struct supports<F(T...)>
: decltype(supports_test(std::declval<F>(), std::declval<T>()...)){};
template<typename F, typename T>
constexpr bool supports_v = supports<F(T, T)>::value;
template<typename F, typename... T>
constexpr bool all_supports_v = (supports<F(T, T)>::value && ...);
现在,MSVC 19.20 已经没有问题了。
但是 GCC 9.1 抱怨说:
In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = supports_v<std::equal_to<void>, A>; _Tp = void]':
error: no type named 'type' in 'struct std::enable_if<false, void>'
既然 SFINAE 知道“no type in struct”应该无声地失败,因为它不是错误,我的问题是我做错了什么吗?
这是我正在使用的示例:
- (海湾合作委员会 9.1)https://godbolt.org/z/LNfjyp
- (MSVC 19.20)https://godbolt.org/z/wJqXFq
正如
作为解决方案,我改为将函数构建为通用支持函数:
template<typename T, bool=supports_v<std::equal_to<>, T>>
struct is_equal_t;
template<typename T>
struct is_equal_t<T, true> {
bool operator() (const T& x, const T& y) const { return x==y; }
};
template<typename T>
struct is_equal_t<T, false> {
bool operator() (const T& x, const T& y) const { return false; }
};
template<typename T>
bool is_equal(const T& x, const T& y) {
static is_equal_t<T> cmp;
return cmp(x, y);
}