别名模板,部分特化和无效参数类型void

sky*_*ack 10 c++ templates void c++11 template-aliases

请考虑以下代码:

template<typename F>
struct S;

template<typename Ret, typename... Args>
struct S<Ret(Args...)> { };

template<typename... Args>
using Alias = S<void(Args...)>;

int main() {
    S<void(int)> s;
    Alias<int> alias;
}
Run Code Online (Sandbox Code Playgroud)

它正常工作,如预期的那样,涉及的线S和涉及Alias引擎盖的相同类型S<void(int)>.

现在,请考虑以下更改:

int main() {
    S<void(void)> s;  // this line compiles
    Alias<void> alias;  // this line does not
}
Run Code Online (Sandbox Code Playgroud)

我期望它编译,原因与上面提到的类似.
不言而喻,由于涉及到行,它不会编译Alias,而是我收到错误:

用'Alias = S [with Args = {void}]代替'模板'

[...]

错误:参数类型无效'void'

问题很简单:我错过了什么?

Bar*_*rry 5

来自[dcl.fct],强调我的:

非依赖类型的单个未命名参数组成的参数列表void等同于空参数列表.除了这种特殊情况,参数不应具有类型cv void.

在这种情况下,Args...是一个依赖类型包,因此void不允许.这个想法在[temp.deduct]的注释中重复:

[注意:由于以下原因,类型推导可能会失败:
- [...]
- 尝试创建一个函数类型,其中参数的类型为void,或者返回类型是函数类型或数组类型.
- [...] - 后
注]

请注意,S<void(void)>编译因为void(void)是非依赖的并且是等价的void(),所以Ret(Args...)永远不会推导出void在参数列表中 - 它是用Args...空推导出来的.


至少有一个简单的解决方法,你可以写Alias<>.