可变函数/非可变模板之间函数类型衰减的不一致性?

时间:2016-08-31 02:09:24

标签: c++ c++11 language-lawyer variadic-templates function-templates

给定非可变函数模板:

template<class T>
void f(void(t)(T));

还有一些简单的功能:

void f1(int);
void f2(char);

这有效:

f(f1);

t的类型变为void (*)(int)

然而,可变对应物:

template<class... T>
void f(void(...t)(T));

// call
f(f1, f2);

不起作用。编译器(gcc&amp; clang)抱怨不匹配的类型void(T)void (*)(int)。请参阅DEMO

请注意,如果明确添加*,则可以正常使用:

template<class... T>
void f(void(*...t)(T));

那么,为什么非可变参数可以衰减函数类型而可变参数不能?

3 个答案:

答案 0 :(得分:3)

AFAICS,代码很好(同样由VC++ICC编译它的事实支持)。毕竟,模板参数推导似乎与函数类型一样,就像它对函数指针或引用类型一样; [temp.deduct.type]/18

  

template-argument 可以从函数类型中推断出来。

[temp.deduct.call]/1

  

对于出现在 parameter-declaration-list 末尾的函数参数包,   对于调用的每个剩余参数执行推导,获取 declarator-id 的类型P   函数参数包作为相应的函数模板参数类型。每个扣除推断   由函数扩展的模板参数包中后续位置的模板参数   参数包。

特别是后一段确认存在一些不一致性,因为在第二种情况下({1}}包的(不成功)扣除减少到案例1中的(成功)扣除。

我的猜测是Clang和GCC在声明时就拒绝了函数模板的参数类型,但是当参数是包扩展(然后无法推断)时拒绝这样做。当我们将样本调用改为T时,Clang的错误消息是

  

注意:候选模板已被忽略:无法将f(f1)'void (T)'

匹配

所以这个论点实际上是在扣除之前就已经腐朽了。

答案 1 :(得分:0)

因为你的语法不太正确。

template<class... T>
void f(void(t)(T...));

void f1(int);

void foo()
{
    f(f1);
}

使用gcc 6.1.1测试。编译没有错误。

在非变量版本中,您使用模板参数作为传递函数参数的参数的参数。

因此,对于可变参数版本,参数包扩展的位置。

答案 2 :(得分:0)

这解释了吗?

var a = 0;
var b = 0;
var z = 0;
var x = 0;
function findOutlier(integers){
  //your code here
while(x < integers.length){
 	  if(integers[x]%2 === 0){
 	  	 a = x;
 	  	 z = z + 1;
 	  }
	  else{
	  	b = x;
	  }
      x = x + 1
	  
}
if(z === 1){return integers[a]}
else{return integers[b]}
	
}
findOutlier([2,6,8,10,3]);