C ++中可变数量的参数? [c++]


Answers

C ++ 11中,您有两个新选项,因为“ 替代”部分中Variadic函数参考页面显示:

  • 变量模板也可用于创建可变数量的参数的函数。 它们往往是更好的选择,因为它们不对参数的类型施加限制,不执行积分和浮点促销,并且是类型安全的。 (因为C ++ 11)
  • 如果所有变量参数共享一个公共类型,std :: initializer_list为访问变量参数提供了一个方便的机制(尽管有不同的语法)。

下面是一个示例,显示了两种替代方案( 见实时 ):

#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 } ) ;
} 

如果您使用gccclang我们可以使用PRETTY_FUNCTION 魔术变量显示函数的类型签名,这有助于了解发生了什么。 例如使用:

std::cout << __PRETTY_FUNCTION__ << ": " << t <<std::endl ;

将在示例中对可变参数进行跟踪( 请参见实时 ):

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或其他标准容器之一

#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 ) ;
}

可变模板的替代方案将是可变的函数,尽管它们不是类型安全的,并且一般来说容易出错,并且可能不安全地使用,但是唯一其他潜在的替代方案是使用默认参数 ,尽管它的使用有限。 下面的示例是链接引用中的示例代码的修改版本:

#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 ;
} 

使用可变函数也可以通过参数中的限制,这些参数在第5.2.2节中的C ++标准草案中详细描述。 函数调用7段:

当给定参数没有参数时,参数的传递方式是接收函数可以通过调用va_arg(18.7)来获取参数的值。 对参数表达式执行lvalue-to-rvalue(4.1),数组到指针(4.2)和函数到指针(4.3)的标准转换。 在这些转换之后,如果参数没有算术,枚举,指针,指向成员或类类型的指针,那么程序是不完整的。 如果参数具有非POD类类型(第9节),行为是未定义的。 [...]

Question

我如何编写一个接受可变数量参数的函数? 这是可能的吗?




在C ++ 11中,有一种可变参数模板的方法,导致一个非常优雅和类型安全的方法来实现变量参数的功能。 Bjarne本人在C ++ 11FAQ中给出了一个使用可变参数模板printf的一个很好的例子。

就个人而言,我认为这样优雅,直到该编译器支持C ++ 11变量参数模板,我甚至不会在C ++中调用变量参数函数。




唯一的方法是通过使用C风格的变量参数,如这里所述。 请注意,这不是推荐的做法,因为它不是类型安全和容易出错的。




您可能需要重载或默认参数 - 使用默认参数定义相同的功能:

void doStuff( int a, double termstator = 1.0, bool useFlag = true )
{
   // stuff
}

void doStuff( double std_termstator )
{
   // assume the user always wants '1' for the a param
   return doStuff( 1, std_termstator );
}

这将允许您使用四个不同的调用之一调用该方法:

doStuff( 1 );
doStuff( 2, 2.5 );
doStuff( 1, 1.0, false );
doStuff( 6.72 );

...或者你可能正在从C寻找v_args调用约定。




正如其他人所说,C风格的变量。 但是您也可以使用默认参数进行类似操作。




如果所有参数都是const并且类型相同,我们也可以使用initializer_list