在 C++11 中,您有两个新选项,正如 Alternatives 部分中的 Variadic arguments 参考页面 所述:
- 可变参数模板也可用于创建采用可变数量的函数
论据。它们通常是更好的选择,因为它们不会对
参数的类型,不执行整数和浮点提升,以及
是类型安全的。 (C++11 起)
- 如果所有变量参数共享一个公共类型,则 std::initializer_list 提供一个
访问变量参数的便捷机制(尽管语法不同)。
以下是显示两种选择的示例 (see it live):
#include <iostream>
#include <string>
#include <initializer_list>
template <typename T>
void func(T t)
{
std::cout << t << std::endl ;
}
template<typename T, typename... Args>
void func(T t, Args... args) // recursive variadic function
{
std::cout << t <<std::endl ;
func(args...) ;
}
template <class T>
void func2( std::initializer_list<T> list )
{
for( auto elem : list )
{
std::cout << elem << std::endl ;
}
}
int main()
{
std::string
str1( "Hello" ),
str2( "world" );
func(1,2.5,'a',str1);
func2( {10, 20, 30, 40 }) ;
func2( {str1, str2 } ) ;
}
如果您使用gcc 或clang,我们可以使用PRETTY_FUNCTION magic variable 来显示函数的类型签名,这有助于理解正在发生的事情。例如使用:
std::cout << __PRETTY_FUNCTION__ << ": " << t <<std::endl ;
对于示例中的可变参数函数(see it live)将导致 int 如下:
void func(T, Args...) [T = int, Args = <double, char, std::basic_string<char>>]: 1
void func(T, Args...) [T = double, Args = <char, std::basic_string<char>>]: 2.5
void func(T, Args...) [T = char, Args = <std::basic_string<char>>]: a
void func(T) [T = std::basic_string<char>]: Hello
在 Visual Studio 中,您可以使用 FUNCSIG。
更新 Pre C++11
Pre C++11 std::initializer_list 的替代品将是 std::vector 或其他 standard containers 之一:
#include <iostream>
#include <string>
#include <vector>
template <class T>
void func1( std::vector<T> vec )
{
for( typename std::vector<T>::iterator iter = vec.begin(); iter != vec.end(); ++iter )
{
std::cout << *iter << std::endl ;
}
}
int main()
{
int arr1[] = {10, 20, 30, 40} ;
std::string arr2[] = { "hello", "world" } ;
std::vector<int> v1( arr1, arr1+4 ) ;
std::vector<std::string> v2( arr2, arr2+2 ) ;
func1( v1 ) ;
func1( v2 ) ;
}
可变参数模板的替代方案是variadic functions,尽管它们不是类型安全的,通常是error prone and can be unsafe to use,但唯一的其他潜在替代方案是使用默认参数,尽管它的用途有限。下面的示例是链接参考中示例代码的修改版本:
#include <iostream>
#include <string>
#include <cstdarg>
void simple_printf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
while (*fmt != '\0') {
if (*fmt == 'd') {
int i = va_arg(args, int);
std::cout << i << '\n';
} else if (*fmt == 's') {
char * s = va_arg(args, char*);
std::cout << s << '\n';
}
++fmt;
}
va_end(args);
}
int main()
{
std::string
str1( "Hello" ),
str2( "world" );
simple_printf("dddd", 10, 20, 30, 40 );
simple_printf("ss", str1.c_str(), str2.c_str() );
return 0 ;
}
使用 可变参数函数 还附带对您可以传递的参数的限制,这在 draft C++ standard 部分 5.2.2 中进行了详细说明 函数调用 段落 7 :
当给定参数没有参数时,参数的传递方式使得接收函数可以通过调用 va_arg (18.7) 来获取参数的值。左值到右值 (4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 标准转换是在参数表达式上执行的。在这些转换之后,如果参数没有算术、枚举、指针、指向成员的指针或类类型,则程序是非良构的。如果参数具有非 POD 类类型(第 9 条),则行为未定义。 [...]