《C++ Primer 第五版》省略符号(...)
在 C 语言里:可变参数函数(printf
风格)
在 C 语言里,省略号 ...
出现在函数参数列表里,表示参数个数不固定。
最典型的例子就是 printf
:
#include <stdio.h>
#include <stdarg.h>void myPrint(const char *fmt, ...) { // ... 表示不定数量参数va_list args;va_start(args, fmt);while (*fmt) {if (*fmt == 'd') {int i = va_arg(args, int);printf("%d\n", i);}fmt++;}va_end(args);
}int main() {myPrint("ddd", 10, 20, 30); // 传了三个 intreturn 0;
}
🔑 要点:
...
代表“剩下的参数”需要
<stdarg.h>
里的宏 (va_list
,va_start
,va_arg
,va_end
) 才能取出缺点:类型不安全,编译器不会检查传入的类型(传错类型可能崩溃)
2️⃣ 在 C++ 语言里:模板参数包(可变参数模板)
C++11 引入了 可变参数模板,也是用 ...
。
和 C 不同,它是编译期展开,类型安全。
例子:
#include <iostream>
using namespace std;void print() { } // 递归出口template<typename T, typename... Args>
void print(T first, Args... rest) {cout << first << " ";print(rest...); // 展开递归
}int main() {print(1, 2.5, "hello", 'A'); // 任意类型,安全return 0;
}
输出:
1 2.5 hello A
🔑 要点:
typename... Args
定义一个参数包rest...
展开这个参数包类型安全,编译器会检查每个实参的类型
3️⃣ 在函数调用里:参数包展开
C++ 里 ...
还能用来 展开一组参数。
例子:
template<typename... Args>
void call(Args... args) {foo(args...); // 把参数原样传给 foo
}
4️⃣ 其他用法:折叠表达式(C++17)
C++17 引入了 折叠表达式,简化了可变参数的处理:
template<typename... Args>
int sum(Args... args) {return (args + ...); // 从左到右展开:((a+b)+c)+d ...
}int main() {cout << sum(1,2,3,4,5) << endl; // 15
}
相比递归调用更优雅。
5️⃣ 总结口诀
C 的
...
= “袋子”,丢多少个参数进去都行,但取出来要小心(用va_arg
),类型不安全。C++ 的
...
= “魔法展开符”,可以把一包模板参数展开成一串,既灵活又安全。C++17 之后,还能写折叠表达式,更简洁。
👉 形象比喻:
C 的
...
像是快递袋子,里面放什么快递员不管,你自己拆开得对照单子,不然拆错了就坏了。C++ 的
...
像是拼装积木,编译器帮你一块块展开拼起来,不会出错。