我的 SFINAE 出了啥问题?:测试支持的运算符

Posted

技术标签:

【中文标题】我的 SFINAE 出了啥问题?:测试支持的运算符【英文标题】:What's wrong with my SFINAE?: Testing Supported Operators我的 SFINAE 出了什么问题?:测试支持的运算符 【发布时间】:2019-10-26 07:20:06 【问题描述】:

这是有问题的代码:

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 抱怨:

使用 enable_if_t = typename std::enable_if::type [with bool _Cond = supports_v<:equal_to>, A> 替换 'template; _Tp = void]':

错误:'struct std::enable_if'中没有​​名为'type'的类型

由于 SFINAE 知道“结构中没有类型”应该静默失败,因为它不是错误,所以我的问题是我做错了什么吗?

这是我正在使用的示例:

(GCC 9.1)https://godbolt.org/z/LNfjyp (MSVC 19.20)https://godbolt.org/z/wJqXFq

【问题讨论】:

你能提供一个minimal reproducible example吗?像第二个alreadyValue 重载大概应该是一个模板,等等。 我建议在这种情况下使用if constexpr。更容易阅读。见***.com/a/51659883/2466431 @JVApen,谢谢,我从来不知道我可以像这样内联一个 constexpr。 对于 SFINAE,您需要未评估的上下文和依赖类型。你似乎两者都没有。你想要完成什么?至于为什么 MSVC 接受这个。好吧,它只是不是一个很好的 C++ 编译器。尤其是如果你去做这些事情。 就目前而言,T 是类的模板参数,而不是方法(显然)。这可能与以下question有关。 【参考方案1】:

正如@rubenvb 和@Mike Spencer 所暗示的那样, 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);

【讨论】:

以上是关于我的 SFINAE 出了啥问题?:测试支持的运算符的主要内容,如果未能解决你的问题,请参考以下文章

URI 中的版本不受支持的 API 版本——出了啥问题?

一些测试用例失败了。告诉我出了啥问题

MG7580支持代码6502是出了啥故障

我的 SQL 查询出了啥问题?

我的 Android 通知计划功能出了啥问题?

我的 IF 语句出了啥问题并且是数字