T240102 What does the …… mean in C++?
不知大家是否遇到过这样的代码:
template <class... Args>
void f(Args......) {}
参数包后面紧跟着 6 个 .
,一般不是用 ...
来扩展参数包吗?这是什么鬼东西?
这个其实可以称为 Two ellipsis operators(非正式称谓),虽说极其罕见,但却是 C++11 标准的一部分,见 [dcl.fct]/3:
parameter-declaration-clause:
parameter-declaration-listopt …opt
parameter-declaration-list , …
也就是说,它其实是 ..., ...
的省略写法。以下这三种写法完全等价:
template <class... Args> void f(Args......) {}
template <class... Args> void f(Args... ...) {}
template <class... Args> void f(Args..., ...) {}
而 ......
是最简洁的写法,多为使用。那么它有什么作用呢?
这又是向后兼容 C 的产物,第一个 ...
用于扩展 C++ 可变模板参数包,第二个 ...
则用于匹配 C Variadic functions[1] 中的旧式变参。
主要目的就在于识别 C Variadic functions,举个例子:
template <class... Args>
void f(void (*fp)(Args...)) {
std::cout << "#1\n";
}
template <class... Args>
void f(void (*fp)(Args......)) {
std::cout << "#2\n";
}
void g(int, float) {}
void h(int, ...) {}
int main() {
f(&g); // calls #1
f(&h); // calls #2
}
早期 std::is_function
[2] 的实现就使用这一手法来识别 C Variadic functions。
// primary template
template<class>
struct is_function : std::false_type {};
// specialization for regular functions
template<class Ret, class... Args>
struct is_function<Ret(Args...)> : std::true_type {};
// specialization for variadic functions such as std::printf
template<class Ret, class... Args>
struct is_function<Ret(Args......)> : std::true_type {};
// ...
因此,它才能识别 printf/fprintf
这些旧式可变函数。不过,早期这种实现太过麻烦,如今利用概念直接求解,变得极为简单:
template<class T>
struct is_function : std::integral_constant<
bool,
!std::is_const<const T>::value && !std::is_reference<T>::value
> {};