这与问题类似,但情况更为具体。这一次,编译器不像预期的那样工作。
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?
}在上面的示例中,不能推导参数pack T,但是编译器应该能够在使用显式参数替换pack T (本例中是单个int )之后推断出U。
在没有nondeduced_t技巧的情况下,上面的操作也是可行的:
template<class... T, class U>
void f(void(*)(T..., U)) {}因为根据T,参数包[temp.deduct.type]p5已经处于非推导的上下文中。
未推导的上下文如下:
不幸的是,我测试过的编译器(g++/clang)都不接受该代码。值得注意的是,下面这样的内容既适用于g++也适用于clang。
template<class... T>
void f(void(*)(nondeduced_t<T>..., char)) {}再说一次,这两种方法都行不通:
template<class... T>
void f(void(*)(T..., char)) {}我的期望错了吗?
发布于 2016-08-23 21:30:58
由[temp.deduct.type]p5提供的非推导上下文之一是
一个函数参数包,它不会出现在参数声明列表的末尾。
不作为模板函数的最后一个参数出现的参数包永远不会被推导出来,但是指定禁用演绎的参数类型是完全正确的。e.g
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但是,改变函数参数的顺序,甚至保留模板参数,消除了非推导的上下文条件,打破了参数包的无限扩展。e.g
template<class T1, class ... Types> void g1(T1, Types ...);
g1(1,2,3) // works because its a deduced context.您的代码不编译有两个原因:
为了使代码编译,您可以放置参数包的展开,因为它忘记了nondeduced_t间接,如
template<class... T,class U>
void f( void(*)(U,T...) ) { }
f(g);或更改模板参数的顺序并在函数调用中指定模板参数,如
template<class U,class... T>
void f( void(*)(U,typename nondeduced<T>::type...) ) {}
f<int,char>(g); https://stackoverflow.com/questions/39104749
复制相似问题