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]:
- 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.
包扩展由模式和省略号组成,其实例化在列表中产生零个或多个模式的实例化。模式的形式取决于扩展发生的环境。
...
- 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.
包扩展的实例化既不是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]:
- 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.
包扩展由模式和省略号组成,其实例化在列表中产生零个或多个模式的实例化。模式的形式取决于扩展发生的环境。
...
- 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.
包扩展的实例化既不是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。