Jam*_*ree 13 c++ language-lawyer variadic-templates c++11 template-argument-deduction
这类似于问题,但更具体的情况.这次,没有编译器按预期工作.
template<class T>
struct nondeduced
{
using type = T;
};
template<class T>
using nondeduced_t = typename nondeduced<T>::type;
template<class... T, class U>
void f(void(*)(nondeduced_t<T>..., U)) {}
void g(int, char) { }
int main()
{
f<int>(g); // error?
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,T
无法推导出参数包,但编译器应该能够U
在显式参数替换pack之后推导出T
(即int
在这种情况下为single ).
预计上述内容也可以在没有nondeduced_t
诀窍的情况下工作:
template<class... T, class U>
void f(void(*)(T..., U)) {}
Run Code Online (Sandbox Code Playgroud)
因为T
根据[temp.deduct.type] p5,参数包已经在非推导的上下文中
未推断的上下文是:
- 函数参数包,不会出现在参数声明列表的末尾.
不幸的是,我测试过的编译器(g ++/clang)都没有接受代码.值得注意的是,下面的内容适用于g ++和clang.
template<class... T>
void f(void(*)(nondeduced_t<T>..., char)) {}
Run Code Online (Sandbox Code Playgroud)
而且,这对两者都不起作用:
template<class... T>
void f(void(*)(T..., char)) {}
Run Code Online (Sandbox Code Playgroud)
我的期望是错的吗?
通过[temp.deduct.type]p5,非推导上下文之一是
不出现在参数声明列表末尾的函数参数包。
不作为模板函数的最后一个参数出现的参数包永远不会被推导,但指定禁用推导的参数类型是完全正确的。例如
template<class T1, class ... Types> void g1(Types ..., T1);
g1<int, int, int>(1,2,3); // works by non-deduction
g1(1,2,3) // violate the rule above by non-deduced context
Run Code Online (Sandbox Code Playgroud)
但是改变函数参数的顺序,甚至保留模板参数不变,删除了非推导的上下文条件并打破了参数包的无限扩展。例如
template<class T1, class ... Types> void g1(T1, Types ...);
g1(1,2,3) // works because its a deduced context.
Run Code Online (Sandbox Code Playgroud)
您的代码无法编译的原因有两个:
函数参数的顺序创建了一个非推导上下文,这导致函数f中指定的模式中的参数包T的类型永远不会被推导。
模板参数 T 仅作为函数参数中的限定符出现(例如nondeduced_t),而不直接指定为函数参数(允许参数推导)。
要使代码编译,您可以放置参数包的扩展,因为它忘记了nonduced_t间接,如
template<class... T,class U>
void f( void(*)(U,T...) ) { }
f(g);
Run Code Online (Sandbox Code Playgroud)
或更改模板参数的顺序并在函数调用时指定模板参数,如
template<class U,class... T>
void f( void(*)(U,typename nondeduced<T>::type...) ) {}
f<int,char>(g);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
504 次 |
最近记录: |