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

时间:2020-11-27 18:48:29

Look at this code snippet

看看这段代码

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

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

int main()
{
     Variadic();
}

When I compile it says:

当我编译它时说:

candidate: template void print(T)

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

candidate expects 1 argument, 0 provided

候选人期望1个参数,0提供

And he's right. In fact, I didn't provide any argument in the Parameter Pack.

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

But why, then, this code compiles?

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

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();
}

The first thing I do is to push the first 0 into the initializer_list<>

我做的第一件事是将第一个0推入initializer_list <>

Ok, now let’s move on: the compiler sees

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

(print(args), 0)...

It tries to call print()… oh wait… the Parameter Pack is empty and the print() function takes 1 parameter.

它试图调用print()...哦等等......参数包是空的,print()函数有1个参数。

Why does it evaluate to auto x = {0};, then?

为什么它会评估为自动x = {0};然后呢?

Why doesn't the compiler give me the exact same error as before?

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

2 个解决方案

#1


5  

You misunderstand how the ... expansion operator works. In your example, when args is an empty pack, (print(args), 0)... expands to nothing, not print().

你误解了...扩展运算符是如何工作的。在你的例子中,当args是一个空包时,(print(args),0)...扩展为空,而不是print()。

If args was given as x it would expand to print(x), 0.

如果args给出为x,它将扩展为print(x),0。

If args was given as x, y it would expand to (print(x), 0), (print(y), 0).

如果args以x,y给出,它将扩展为(print(x),0),(print(y),0)。

etc.

Basically it expands all of the expression that contains args and it is applied to, not just the args bit itself.

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

From the standard [temp.variadic]:

从标准[temp.variadic]:

  1. A pack expansion consists of a pattern and an ellipsis, the instantiation of which produces zero or more instantiations of the pattern in a list. The form of the pattern depends on the context in which the expansion occurs.
  2. 包扩展由模式和省略号组成,其实例化在列表中产生零个或多个模式的实例化。模式的形式取决于扩展发生的环境。

...

  1. The instantiation of a pack expansion that is neither a sizeof... expression nor a fold-expression produces a list E1, E2, ..., EN , where N is the number of elements in the pack expansion parameters. Each Ei is generated by instantiating the pattern and replacing each pack expansion parameter with its ith element.
  2. 包扩展的实例化既不是sizeof ...表达式也不是fold-expression产生列表E1,E2,...,EN,其中N是包扩展参数中的元素数。通过实例化模式并用其第i个元素替换每个包扩展参数来生成每个Ei。

#2


1  

According to the C++ standard 14.5.3/p4 Variadic templates [temp.variadic] (Emphasis Mine):

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

A pack expansion consists of a pattern and an ellipsis, the instantiation of which produces zero or more instantiations of the pattern in a list (described below). The form of the pattern depends on the context in which the expansion occurs.

包扩展由模式和省略号组成,其实例化在列表中产生零个或多个模式的实例化(如下所述)。模式的形式取决于扩展发生的环境。

Notice the zero or more. In your case there's an empty pack so instantiations of the pattern (print(args), 0)... are zero. Consequently, you don't get a compile time error because expression:

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

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

actually evaluates to:

实际评估为:

auto x = {0};

that is, print is never called in the code generated by the compiler.

也就是说,从不在编译器生成的代码中调用print。

#1


5  

You misunderstand how the ... expansion operator works. In your example, when args is an empty pack, (print(args), 0)... expands to nothing, not print().

你误解了...扩展运算符是如何工作的。在你的例子中,当args是一个空包时,(print(args),0)...扩展为空,而不是print()。

If args was given as x it would expand to print(x), 0.

如果args给出为x,它将扩展为print(x),0。

If args was given as x, y it would expand to (print(x), 0), (print(y), 0).

如果args以x,y给出,它将扩展为(print(x),0),(print(y),0)。

etc.

Basically it expands all of the expression that contains args and it is applied to, not just the args bit itself.

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

From the standard [temp.variadic]:

从标准[temp.variadic]:

  1. A pack expansion consists of a pattern and an ellipsis, the instantiation of which produces zero or more instantiations of the pattern in a list. The form of the pattern depends on the context in which the expansion occurs.
  2. 包扩展由模式和省略号组成,其实例化在列表中产生零个或多个模式的实例化。模式的形式取决于扩展发生的环境。

...

  1. The instantiation of a pack expansion that is neither a sizeof... expression nor a fold-expression produces a list E1, E2, ..., EN , where N is the number of elements in the pack expansion parameters. Each Ei is generated by instantiating the pattern and replacing each pack expansion parameter with its ith element.
  2. 包扩展的实例化既不是sizeof ...表达式也不是fold-expression产生列表E1,E2,...,EN,其中N是包扩展参数中的元素数。通过实例化模式并用其第i个元素替换每个包扩展参数来生成每个Ei。

#2


1  

According to the C++ standard 14.5.3/p4 Variadic templates [temp.variadic] (Emphasis Mine):

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

A pack expansion consists of a pattern and an ellipsis, the instantiation of which produces zero or more instantiations of the pattern in a list (described below). The form of the pattern depends on the context in which the expansion occurs.

包扩展由模式和省略号组成,其实例化在列表中产生零个或多个模式的实例化(如下所述)。模式的形式取决于扩展发生的环境。

Notice the zero or more. In your case there's an empty pack so instantiations of the pattern (print(args), 0)... are zero. Consequently, you don't get a compile time error because expression:

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

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

actually evaluates to:

实际评估为:

auto x = {0};

that is, print is never called in the code generated by the compiler.

也就是说,从不在编译器生成的代码中调用print。