initializer_list
If the number of parameters of the function is unknown but all parameters are of the same type, we can use the parameter of type initializer_list. initializer_list is a standard library type used to represent an array of values of a certain type.
Like vector, initializer_list is also a template type, but the elements in the initializer_list object are always constant values, where begin() returns a pointer to the first element of the list, and end() returns a pointer to the tail element of the list.
Objects of the same type will be implicitly converted to initializer_list when placed in curly braces. When overloading occurs, this expression will match initializer_list first rather than vector.
ellipsis parameter
If the number of parameters of the function is unknown but the types of the parameters may be different, you can use the ellipsis formal parameter or variable parameter template. The ellipsis formal parameter is a function of the C standard library, so for the case where the parameter types are different but the number is unknown, we Use variadic templates whenever possible.
An ellipsis parameter can only appear in the last position in the parameter list, and at least one parameter must be defined before it.
The macros related to ellipsis formal parameters are as follows:
- void va_start(va_list ap, last_arg) Initializes the ap variable, which is used together with the va_arg and va_end macros. last_arg is the last known fixed argument passed to the function, the one before the ellipsis. This macro must be called before using va_arg and va_end.
- type va_arg(va_list ap, type) Retrieves the next argument of type type in the function's argument list. It cannot tell if the retrieved argument was the last argument passed to the function.
- void va_end(va_list ap) Allows a function with variable arguments using the va_start macro to return. If va_end is not called before returning from the function, the result is undefined.
case:
//initializer parameterized list void printStr(initializer_list<std::string> str) { cout << "initializer=======" << endl; for (auto it = str.begin(); it != str.end(); it++) { cout << "printStr:"<<*it << endl; } } void printStr(vector<std::string> str) { cout << "vector=======" << endl; for (auto it = str.begin(); it != str.end(); it++) { cout << "printStr:" << *it << endl; } } void printStr(string s,initializer_list<std::string> str) { for (auto it = str.begin(); it != str.end(); it++) { cout << "s:" << s; cout << "printStr:" << *it << endl; } } //... variadic C-style #include <stdarg.h> //The comma before the ellipsis can be omitted, and the following two writing methods are supported //void printStrC(const char* format...) void printStrC(const char* format, ...) { va_list vlist; va_start(vlist, format); char buf[100]; vsprintf_s(buf, format, vlist); va_end(vlist); std::cout << buf << endl; } //The comma before the ellipsis can be omitted, and the following two writing methods are supported //void printFloatsC(int n...) void printFloatsC(int n, ...) { va_list vlist; va_start(vlist, n); for (size_t i = 0; i < n; i++) { double d = va_arg(vlist, double); cout << d << " "; } cout << endl; va_end(vlist); } int main() { //initializer cout << "==initializer=="<<endl; printStr(std::vector<string>{"aaa","bbb","ccc"}); printStr({"aaa", "bbb", "ccc"}); printStr("222",{ "aaa","bbb","ccc" }); //"C" cout << "==C==" << endl; printStrC("printStrC:%s,%d,%f", "1111", 222,33.123); printFloatsC(3, 1.123, 2.123, 3.123); return 0; }
result:
==initializer== vector======= printStr:aaa printStr:bbb printStr:ccc initializer======= printStr:aaa printStr:bbb printStr:ccc s:222printStr:aaa s:222printStr:bbb s:222printStr:ccc ==C== printStrC:1111,222,33.123000 1.123 2.123 3.123 Please press any key to continue. . .
Varargs macros: ... and __VA_ARGS__
#define PR(...) printf(__VA_ARGS__)
PR("Howdy"); PR("Weight = %d, shipping = $%.2f\n", wt, sp);
#include <stdio.h> #include <math.h> #define PR(X, ...) printf("Message " #X ": " __VA_ARGS__) int main(void) { double x = 48; double y; y = sqrt(x); PR(1, "x = %g\n", x); PR(2, "x = %.2f, y = %.4f\n", x, y); return 0; }
The output of this program is as follows:
Message 1: x = 48 Message 2: x = 48.00, y = 6.9282
Enhanced version variable parameter macro: ##__VA_ARGS__
##__VA_ARGS__ The function of adding ## in front of the macro is that when the number of variable parameters is 0, the ## here plays the role of removing the redundant "," in front, otherwise a compilation error will occur. Use as follows:
#define edebug(format, ...) fprintf (stderr, format, ##__VA_ARGS__)
If a variable argument is omitted or empty, the ## operator will cause the preprocessor to remove the comma preceding it.
If you do provide some variable parameters when calling the macro, it will put these variable parameters after the comma.
#include <stdio.h> #define LOGFUNC2(fmt,...) (printf(fmt" line:%d - %s/%s \n",##__VA_ARGS__,__LINE__,__TIME__,__DATE__)); int main() { //variable parameter LOGFUNC2("i am C++ :%d name:%s age:%d",112,"C language tutorial",18);// ok //string constant LOGFUNC2("i am C++ ");// ok }
The output of this program is as follows:
i am C++ :112 name:C language tutorial age:18 line:8 - 02:27:52/May 14 2022 i am C++ line:11 - 02:27:52/May 14 2022
//macro variadic #define LOG(...) printf(__VA_ARGS__); #define LOGFUNC2(fmt,...) (printf(fmt" line:%d - %s/%s \n",##__VA_ARGS__,__LINE__,__TIME__,__DATE__)); #define LOGFUNC3(fmt,...) printf("zhengheLINE:%d, " "<=>"fmt" zheng end%d\n",__LINE__,##__VA_ARGS__,__LINE__); #define LOGFUNC4(fmt,...) printf("zhengheLINE:%d, " "<=>"fmt" zheng end%d\n",__LINE__,##__VA_ARGS__,__LINE__); int main() { //macro cout << "==__VA_ARGS__==" << endl; LOG("score is %d\n", 96); //variable parameter LOGFUNC2("i am C++ :%d name:%s age:%d", 112, "C language tutorial", 18);// ok //string constant LOGFUNC2("i am C++ ");// ok LOGFUNC3("==%s==", __FUNCTION__); LOGFUNC4("==%s==%s=", __FUNCTION__,__FILE__); }
result
==__VA_ARGS__== score is 96 i am C++ :112 name:C language tutorial age:18 line:200 - 15:05:52/Jan 18 2023 i am C++ line:202 - 15:05:52/Jan 18 2023 zhengheLINE:203, <=>==main== zheng end203 zhengheLINE:204, <=>==main==d:\projects\consoleapplication1\consoleapplication1\consoleapplication1.cpp= zheng end204
Template variadic parameters
//Template variadic parameters //recursive termination function void ShowListArg() { cout << "non arg:"; cout << endl; } //expansion function template<class T,class ...Args> void ShowListArg(T value,Args... args) { //cout << sizeof...(args) << endl; //Get the number of parameters in the parameter pack cout << "template:"; cout << value<<" "; ShowListArg(args...); } //external call function template<class ...Args> void ShowList(Args ...args) { ShowListArg(args...); } int main() { //Template variadic parameters cout << "==template==" << endl; ShowList(); ShowList(1); ShowList(2, 'A'); ShowList(3, 'A', string("hello")); }
result:
==template== non arg: template:1 non arg: template:2 template:A non arg: template:3 template:A template:hello non arg: