Variadic模板:候选人需要1个参数,0提供(扣除错误)

时间:2016-06-23 15:35:52

标签: c++ templates metaprogramming variadic-templates template-function

请查看此代码段

template<class T> 
void print(T var)
{
    std::cout << var << " ";
}

template<class... Args> 
void Variadic(Args... args)
{
    print(args...);
}

int main()
{
     Variadic();
}

当我编译它时说:

  

候选人:模板无效打印(T)

     

候选人需要1个参数,0提供

他是对的。事实上,我没有在参数包中提供任何参数。

但是,为什么这段代码会编译?

template<class T> 
void print(T var)
{
    std::cout << var << " ";
}

template<class... Args> 
void Variadic(Args... args)
{
    auto x = {0, (print(args), 0)...};
}

int main()
{
     Variadic();
}

我要做的第一件事就是将第一个0推入 initializer_list&lt;&gt;

好的,现在让我们继续:编译器看到

(print(args), 0)...

尝试调用print()...哦等等...... 参数包为空,print()函数为1参数。

为什么它会评估为auto x = {0};呢?

为什么编译器没有给我与以前完全相同的错误?

2 个答案:

答案 0 :(得分:5)

您误解了...扩展运算符的工作原理。在您的示例中,当args为空包时,(print(args), 0)...会扩展为空,而不是print()

如果argsx,则会扩展为print(x), 0

如果argsx, y,则会扩展为(print(x), 0), (print(y), 0)

基本上它扩展了包含args的所有表达式,并且它不仅应用于args位本身。

来自标准[temp.variadic]:

  
      
  1. 包装扩展由图案和省略号组成   实例化产生零或更多的实例化   列表中的模式。模式的形式取决于上下文   发生了扩张。
  2.         

    ...

         
        
    1. 包扩展的实例化既不是sizeof ...表达式也不是fold-expression产生列表E1,E2,...,EN,   其中N是包扩展参数中的元素数。   每个Ei都是通过实例化模式并替换每个模式生成的   使用第i个元素打包扩展参数。
    2.   

答案 1 :(得分:1)

根据C ++ 标准14.5.3 / p4 Variadic模板[temp.variadic] Emphasis Mine ):

  

包扩展包含模式和省略号,   实例化产生零或更多的实例化   列表中的模式(如下所述)。模式的形式取决于   关于扩张发生的背景。

注意零或更多。在你的情况下,有一个空包,因此模式(print(args), 0)...的实例化为零。因此,您没有得到编译时错误,因为表达式:

auto x = {0, (print(args), 0)...};

实际评估为:

auto x = {0};

即,print永远不会在编译器生成的代码中调用。