C++ varargs

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:

Tags: Algorithm C++ programming language

Posted by revez2002 on Thu, 19 Jan 2023 09:37:58 +0530