【问题标题】:How does using ellipses for SFINAE work?在 SFINAE 中使用省略号是如何工作的?
【发布时间】:2016-12-14 12:29:28
【问题描述】:

过去在使用 SFINAE 选择构造函数重载时,我通常使用以下方法:

template <typename T>
class Class {
public:
    template <typename U = T, typename std::enable_if<std::is_void<U>::value, int>::type=0>
    Class() {
        std::cout << "void" << std::endl;
    }

    template <typename U = T, typename std::enable_if<!std::is_void<U>::value, int>::type=0>
    Class() {
        std::cout << "not void" << std::endl;
    }
};

但是,我刚刚遇到了这个替代方案:

template <typename U = T, typename std::enable_if<std::is_void<U>::value>::type...>
Class() {
    std::cout << "void" << std::endl;
}

考虑到以下内容是非法的......

template <typename U = T, void...> // ERROR!
Class() { }

...上面使用省略号而不是非类型模板参数的替代方法如何工作?


完整代码:http://coliru.stacked-crooked.com/a/64a1aaf13ce6099b

【问题讨论】:

  • @peppe 但是template&lt;typename U = T, void&gt; 也是非法的。那不需要使用void 作为类型参数的默认参数吗?如template &lt;typename U = T, typename V = std::enable_if&lt;...&gt;::type&gt;?
  • @peppe 作为模板 type 参数,而不是作为模板非类型参数。
  • @Barry: IOW template&lt;typename std::enable_if&lt;condition&gt;::type&gt; 是非法的,因为如果condition 为真,它会推断出void,因为这是一个非类型参数,而template&lt;typename std::enable_if&lt;condition, int&gt;::type&gt; 是合法的?

标签: c++ c++11 variadic-templates sfinae


【解决方案1】:

我之前的回答是错误的。对不起。我只是要修复它。


此声明:

template <typename U = T, void...>
Class() { }

违反 [temp.res]/8:

程序是 格式错误,不需要诊断,如果 [...] 可变参数模板的每个有效特化都需要一个空模板参数包

它不需要诊断,但编译器无论如何都会选择发出一个。无论哪种方式,代码都是格式错误的。

另一方面

template <typename U = T, std::enable_if_t<std::is_void<U>::value>...>
Class() { }

不违反此要求。我们有一个空包,因此我们不会违反您不能使用 void 作为非类型模板参数的事实。此外,enable_if 的假设特化可以提供一个不存在 void 的类型,因此由于上述限制,它不是格式错误的。

【讨论】:

  • 我已经用enable_if_t&lt;..., int&gt; 测试了代码,clang 也没有编译它,指责Class2&lt;void&gt;Class2&lt;int&gt; 都是模棱两可的。不确定clang是否正确......
  • @W.F.这是一个已知错误,已在主干 IIRC 上修复。
  • @zennehoy 我知道你已经接受了我的回答,但我不太确定这是错的,所以我改变了它。对不起。
  • @Barry 不用担心!我实际上比int=0 变体更喜欢这种语法,所以我很高兴它的格式正确。使用std::enable_if_t 会更好。
  • 我不相信。 std::enable_if 不能专门化,因为 UB 的痛苦,所以即使假设空的 void 包是合法的(我'我也有点怀疑)。
猜你喜欢
  • 2019-10-19
  • 2016-09-12
  • 1970-01-01
  • 1970-01-01
  • 2012-06-01
  • 2023-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多