在查看this问题的同时,我发现自己身处cpp reference site,在那里我发现了一种奇怪的,对我来说很新的语法:
template<class Ret, class... Args>
struct is_function<Ret(Args......)volatile &&> : std::true_type {};
是的,6点!最初我认为这是一个拼写错误,但在再次检查了libstdc ++ source后,就在第444行:
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes......) volatile &&> : public true_type { };
这是一种有效的语法吗?点点,用于打包和解包参数包? 6个点做什么?
答案 0 :(得分:56)
为什么libstdc++
在... ...
的实施中使用is_function
?如果我们查看std::is_function的cppreference部分,它会提供一个示例实现并说明第一个... ...
案例:
// specialization for variadic functions such as std::printf
template<class Ret, class... Args>
struct is_function<Ret(Args......)> : std::true_type {};
所以我们需要第二组...
来匹配像printf
这样的可变函数:
Comma optional as per 8.3.5 [dcl.fct]
|
v
Ret(Args... ...)
^ ^
| |
Match a function with a variable number of arguments
|
and the function is a variadic function
注意,我们有像fprintf
这样的函数,它们在可变参数项之前有两个参数,我们也需要匹配它们。
实际上,如果我们使用该实现并尝试在没有printf
专门化的情况下匹配... ...
,那么它将失败see it live。
此帖C++11's six dots中包含了该语言的一角:
前几天我正在捣乱,发现这个奇怪的小怪:
template <typename... Args> void foo(Args......);
事实证明,......可以完全有效的C ++ 11。当向后兼容性与新的热度混合时会发生这种情况。
//这些都是等价的。
template <typename... Args> void foo1(Args......); template <typename... Args> void foo2(Args... ...); template <typename... Args> void foo3(Args..., ...);
希望最后一个显示这里发生的事情。 [...]
为什么这个有效?我们可以看到, ...
与草案C ++ 11标准部分...
[dcl.fct] 中的8.3.5
同义,后者具有以下语法:< / p>
parameter-declaration-clause:
parameter-declaration-listopt...opt
parameter-declaration-list , ...
并说:
[...]语法正确,“......”不在其中 一个抽象声明符,“,......”与“......”同义。 [...]
答案 1 :(得分:8)
在这种情况下,两者用于不同的目的。第一个用于参数包扩展,第二个用于可变参数列表。该特定声明是处理带有一些常规参数和可变参数列表的函数。
差异在于运行时和编译时的可变性。在运行时获取可变数量参数的函数是特殊的。它是一个单一的函数,可以处理来自调用者的可变数量的参数:
void f(int x,...) // equivalent to void f(int x ...)
{
// Do some run-time logic here to determine what to
// do with parameters after x.
}
这与我们希望能够拥有一个模板的概念截然不同,该模板使用各种函数以及编译时已知的各种参数。例如,我们可以定义一个函数模板,它接受一个指向函数的指针,并允许参数的数量和类型变化:
template <typename... Args>
void g(void (*function_ptr)(Args...))
{
// We can do logic here to call function_ptr with the proper
// number of arguments.
}
鉴于这些功能:
void f1(int);
void f2(int,float);
您可以使用其中任何一个调用g:
g(f1); // fine
g(f2); // also fine
然而
g(f); // error
编译器不知道Args
中g
参数包的用途。