std::enable_if 用于两种不同的方法实现(4 种不同的情况)

Posted

技术标签:

【中文标题】std::enable_if 用于两种不同的方法实现(4 种不同的情况)【英文标题】:std::enable_if for two different methods implementation (4 different cases) 【发布时间】:2018-08-22 08:15:18 【问题描述】:

我需要为 const 和非常量类型实现两种不同的方法。我已经设法编写了工作代码,但我不明白为什么它的某些风格可以,而有些则不行。

这是一个简化的例子,我想知道为什么 #1 有效,但 #2 无效,关于 #3 和 #4 也是如此:

#include <iostream>
#include <vector>

template <typename T>
class X 
public:
    // #1 - works
    template<typename B = T, typename std::enable_if<std::is_const<B>::value, int>::type = 0>
    void foo() std::cout << "CONST" << std::endl;
    template<typename B = T, typename std::enable_if<std::is_const<B>::value == false, int>::type = 0>
    void foo() std::cout << "NON-CONST" << std::endl;

    // #2 - does not work "no type named 'type' in 'std::__1::enable_if<false, int>'; 'enable_if' cannot be used to disable this declaration"
//    template<typename std::enable_if<std::is_const<T>::value, int>::type = 0>
//    void foo() std::cout << "CONST" << std::endl;
//    template<typename std::enable_if<std::is_const<T>::value == false, int>::type = 0>
//    void foo() std::cout << "NON-CONST" << std::endl;

    // #3 - works
//    template<typename B = T, typename = typename std::enable_if<std::is_const<B>::value>::type>
//    void foo() std::cout << "CONST" << std::endl;
//    template<typename B = T, typename std::enable_if<std::is_const<B>::value == false>::type * = nullptr>
//    void foo() std::cout << "NON-CONST" << std::endl;

    // # 4 - does not work - "class member cannot be redeclared"
//    template<typename B = T, typename = typename std::enable_if<std::is_const<B>::value>::type>
//    void foo() std::cout << "CONST" << std::endl;
//    template<typename B = T, typename = typename std::enable_if<std::is_const<B>::value == false>::type>
//    void foo() std::cout << "NON-CONST" << std::endl;
;

int main() 
    X<int> v;
    X<const int> vConst;

    v.foo();
    vConst.foo();

    return 0;

即使有更好的方法来解决我的问题,我也真的很想了解为什么 enable_if 像它一样(而不是)在给出的示例中起作用。

【问题讨论】:

只是风格问题,但更喜欢!condition 而不是condition == false... @Aconcagua:当然,我通常使用!condition,但不幸的是模板代码可能非常复杂,以至于condition == false 对我来说更加可见/可读。 Why doesn't SFINAE (enable_if) work for member functions of a class template?的可能重复 或者,可能是更好的重复匹配:***.com/q/6972368/580083 旁注:如果在非模板函数中使用 constexpr 可能更容易解决问题(仅适用于您不知道的情况......)。 【参考方案1】:

#2 不起作用,因为您遇到了严重故障,因为 T 已由班级修复。

所以你真的有

template<typename std::enable_if<true, int>::type = 0>  // -> template<int = 0>  void foo();
void foo();

template<typename std::enable_if<false, int>::type = 0> // Hard error failure
void foo();

对于#4,默认模板值/类型不是签名的一部分,因此一旦删除,您就有了

template <typename B, typename> void foo() std::cout << "CONST" << std::endl;
template <typename B, typename> void foo() std::cout << "NON-CONST" << std::endl;

具有多个定义的相同方法:您破坏了 ODR。

对于#3,它将是:

template<typename B, typename>
void foo();

template<typename B, typename std::enable_if<std::is_const<B>::value == false>::type *>
void foo();

这是不同的。

【讨论】:

也许在#3 处很有趣,可以更清楚地说明差异:if 第二个foo is 启用,它将到达&lt;typename B, void*&gt; @Aconcagua: 但是签名 differs 在替换之前,例如 Demo 会产生模棱两可的调用(而不是违反 ODR,正如你的句子所暗示的那样)。 不明白为什么我的评论会暗示违反 ODR,我的意图 使不同的签名更加明显...... 我的意思是typename &lt;typename T, std::enable_if_t&lt;cond&lt;T&gt;, int&gt;&gt; voif f()template &lt;typename T, int&gt; void f()是2个不同的签名,即使替换后,它们的结果是一样的。 啊,我明白了...被您的强调误导了(“但签名甚至在之前替换之前也不同”会更明显),但有趣的方面...

以上是关于std::enable_if 用于两种不同的方法实现(4 种不同的情况)的主要内容,如果未能解决你的问题,请参考以下文章

std::enable_if的错误使用方法

对成员变量使用 std::enable_if 或类似方法

SWIG C++/Python 绑定和支持带有 std::enable_if 的条件成员

std::enable_if与boost::enable_if,boost::enable_if_c的区别与联系

std::enable_if与boost::enable_if,boost::enable_if_c的区别与联系

std::enable_if与boost::enable_if,boost::enable_if_c的区别与联系