Variable number of arguments in C++?

C++Variadic Functions

C++ Problem Overview


How can I write a function that accepts a variable number of arguments? Is this possible, how?

C++ Solutions


Solution 1 - C++

In C++11 you have two new options, as the https://en.cppreference.com/w/cpp/language/variadic_arguments">Variadic arguments reference page in the Alternatives section states:

> * Variadic templates can also be used to create functions that take variable number of > arguments. They are often the better choice because they do not impose restrictions on > the types of the arguments, do not perform integral and floating-point promotions, and > are type safe. (since C++11) > * If all variable arguments share a common type, a std::initializer_list provides a > convenient mechanism (albeit with a different syntax) for accessing variable arguments.

Below is an example showing both alternatives (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 } ) ;
} 

If you are using gcc or clang we can use the PRETTY_FUNCTION magic variable to display the type signature of the function which can be helpful in understanding what is going on. For example using:

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

would results int following for variadic functions in the example (see it live):

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

In Visual Studio you can use FUNCSIG.

Update Pre C++11

Pre C++11 the alternative for http://en.cppreference.com/w/cpp/utility/initializer_list">std::initializer_list</a> would be http://en.cppreference.com/w/cpp/container/vector">std::vector</a> or one of the other http://en.cppreference.com/w/cpp/container">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 ) ;
}

and the alternative for variadic templates would be http://en.cppreference.com/w/cpp/utility/variadic">variadic functions although they are not type-safe and in general http://robertseacord.sys-con.com/node/158825/mobile">error prone and can be unsafe to use but the only other potential alternative would be to use default arguments, although that has limited use. The example below is a modified version of the sample code in the linked reference:

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

Using variadic functions also comes with restrictions in the arguments you can pass which is detailed in the http://www.open-std.org/Jtc1/sc22/wg21/docs/papers/2005/n1804.pdf">draft C++ standard in section 5.2.2 Function call paragraph 7:

>When there is no parameter for a given argument, the argument is passed in such a way that the receiving function can obtain the value of the argument by invoking va_arg (18.7). The lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the argument expression. After these conversions, if the argument does not have arithmetic, enumeration, pointer, pointer to member, or class type, the program is ill-formed. If the argument has a non-POD class type (clause 9), the behavior is undefined. [...]

Solution 2 - C++

You probably shouldn't, and you can probably do what you want to do in a safer and simpler way. Technically to use variable number of arguments in C you include stdarg.h. From that you'll get the va_list type as well as three functions that operate on it called va_start(), va_arg() and va_end().

#include<stdarg.h>

int maxof(int n_args, ...)
{
    va_list ap;
    va_start(ap, n_args);
    int max = va_arg(ap, int);
    for(int i = 2; i <= n_args; i++) {
        int a = va_arg(ap, int);
        if(a > max) max = a;
    }
    va_end(ap);
    return max;
}

If you ask me, this is a mess. It looks bad, it's unsafe, and it's full of technical details that have nothing to do with what you're conceptually trying to achieve. Instead, consider using overloading or inheritance/polymorphism, builder pattern (as in operator<<() in streams) or default arguments etc. These are all safer: the compiler gets to know more about what you're trying to do so there are more occasions it can stop you before you blow your leg off.

Solution 3 - C++

A C++17 solution: full type safety + nice calling syntax

Since the introduction of variadic templates in C++11 and fold expressions in C++17, it is possible to define a template-function which, at the caller site, is callable as if it was a varidic function but with the advantages to:

  • be strongly type safe;
  • work without the run-time information of the number of arguments, or without the usage of a "stop" argument.

Here is an example for mixed argument types

template<class... Args>
void print(Args... args)
{
    (std::cout << ... << args) << "\n";
}
print(1, ':', " Hello", ',', " ", "World!");

And another with enforced type match for all arguments:

#include <type_traits> // enable_if, conjuction

template<class Head, class... Tail>
using are_same = std::conjunction<std::is_same<Head, Tail>...>;

template<class Head, class... Tail, class = std::enable_if_t<are_same<Head, Tail...>::value, void>>
void print_same_type(Head head, Tail... tail)
{
    std::cout << head;
    (std::cout << ... << tail) << "\n";
}
print_same_type("2: ", "Hello, ", "World!");   // OK
print_same_type(3, ": ", "Hello, ", "World!"); // no matching function for call to 'print_same_type(int, const char [3], const char [8], const char [7])'
                                               // print_same_type(3, ": ", "Hello, ", "World!");
                                                                                              ^

More information:

  1. Variadic templates, also known as parameter pack Parameter pack(since C++11) - cppreference.com.
  2. Fold expressions fold expression(since C++17) - cppreference.com.
  3. See a full program demonstration on coliru.

Solution 4 - C++

in c++11 you can do:

void foo(const std::list<std::string> & myArguments) {
   //do whatever you want, with all the convenience of lists
}

foo({"arg1","arg2"});

list initializer FTW!

Solution 5 - C++

In C++11 there is a way to do variable argument templates which lead to a really elegant and type safe way to have variable argument functions. Bjarne himself gives a nice example of printf using variable argument templates in the C++11FAQ.

Personally, I consider this so elegant that I wouldn't even bother with a variable argument function in C++ until that compiler has support for C++11 variable argument templates.

Solution 6 - C++

C-style variadic functions are supported in C++.

However, most C++ libraries use an alternative idiom e.g. whereas the 'c' printf function takes variable arguments the c++ cout object uses << overloading which addresses type safety and ADTs (perhaps at the cost of implementation simplicity).

Solution 7 - C++

Apart from varargs or overloading, you could consider to aggregate your arguments in a std::vector or other containers (std::map for example). Something like this:

template <typename T> void f(std::vector<T> const&);
std::vector<int> my_args;
my_args.push_back(1);
my_args.push_back(2);
f(my_args);

In this way you would gain type safety and the logical meaning of these variadic arguments would be apparent.

Surely this approach can have performance issues but you should not worry about them unless you are sure that you cannot pay the price. It is a sort of a a "Pythonic" approach to c++ ...

Solution 8 - C++

The only way is through the use of C style variable arguments, as described here. Note that this is not a recommended practice, as it's not typesafe and error-prone.

Solution 9 - C++

There is no standard C++ way to do this without resorting to C-style varargs (...).

There are of course default arguments that sort of "look" like variable number of arguments depending on the context:

void myfunc( int i = 0, int j = 1, int k = 2 );

// other code...

myfunc();
myfunc( 2 );
myfunc( 2, 1 );
myfunc( 2, 1, 0 );

All four function calls call myfunc with varying number of arguments. If none are given, the default arguments are used. Note however, that you can only omit trailing arguments. There is no way, for example to omit i and give only j.

Solution 10 - C++

It's possible you want overloading or default parameters - define the same function with defaulted parameters:

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

This will allow you to call the method with one of four different calls:

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

... or you could be looking for the v_args calling conventions from C.

Solution 11 - C++

Using variadic templates, example to reproduce console.log as seen in JavaScript:

Console console;
console.log("bunch", "of", "arguments");
console.warn("or some numbers:", 1, 2, 3);
console.error("just a prank", "bro");

Filename e.g. js_console.h:

#include <iostream>
#include <utility>

class Console {
protected:
	template <typename T>
	void log_argument(T t) {
		std::cout << t << " ";
	}
public:
	template <typename... Args>
	void log(Args&&... args) {
		int dummy[] = { 0, ((void) log_argument(std::forward<Args>(args)),0)... };
		cout << endl;
	}

	template <typename... Args>
	void warn(Args&&... args) {
		cout << "WARNING: ";
		int dummy[] = { 0, ((void) log_argument(std::forward<Args>(args)),0)... };
		cout << endl;
	}

	template <typename... Args>
	void error(Args&&... args) {
		cout << "ERROR: ";
		int dummy[] = { 0, ((void) log_argument(std::forward<Args>(args)),0)... };
		cout << endl;
	}
};

Solution 12 - C++

C++ 11 with color code support

  • Is generic and works for all dataypes
  • Works like JavaScript console.log(1,"23")
  • Supports color codes for info, warning, error.
  • Example:
    enter image description here
#pragma once
#include <iostream>
#include <string>

const std::string RED = "\e[0;91m";
const std::string BLUE = "\e[0;96m";
const std::string YELLOW = "\e[0;93m";

class Logger {
private:
  enum class Severity { INFO, WARN, ERROR };

  static void print_colored(const char *log, Severity severity) {
    const char *color_code = nullptr;

    switch (severity) {
    case Severity::INFO:
      color_code = BLUE.c_str();
      break;
    case Severity::WARN:
      color_code = YELLOW.c_str();
      break;
    case Severity::ERROR:
      color_code = RED.c_str();
      break;
    }

    std::cout << "\033" << color_code << log << "\033[0m -- ";
  }

  template <class Args> static void print_args(Args args) {
    std::cout << args << " ";
  }

public:
  template <class... Args> static void info(Args &&...args) {
    print_colored("[INFO] ", Severity::INFO);
    int dummy[] = {0, ((void)print_args(std::forward<Args>(args)), 0)...};
    std::cout << std::endl;
  }

  template <class... Args> static void warn(Args &&...args) {
    print_colored("[WARN] ", Severity::WARN);
    int dummy[] = {0, ((void)print_args(std::forward<Args>(args)), 0)...};
    std::cout << std::endl;
  }

  template <class... Args> static void error(Args &&...args) {
    print_colored("[ERROR]", Severity::ERROR);
    int dummy[] = {0, ((void)print_args(std::forward<Args>(args)), 0)...};
    std::cout << std::endl;
  }
};

Solution 13 - C++

If you know the range of number of arguments that will be provided, you can always use some function overloading, like

f(int a)
    {int res=a; return res;}
f(int a, int b)
    {int res=a+b; return res;}

and so on...

Solution 14 - C++

As others have said, C-style varargs. But you can also do something similar with default arguments.

Solution 15 - C++

// spawn: allocate and initialize (a simple function)
template<typename T>
T * spawn(size_t n, ...){
  T * arr = new T[n];
  va_list ap;
  va_start(ap, n);
  for (size_t i = 0; i < n; i++)
    T[i] = va_arg(ap,T);
  return arr;
}

User writes:

auto arr = spawn<float> (3, 0.1,0.2,0.3);

Semantically, this looks and feels exactly like an n-argument function. Under the hood, you might unpack it one way or the other.

Solution 16 - C++

It is possible now...using boost any and templates In this case, arguments type can be mixed

#include <boost/any.hpp>
#include <iostream>
    
#include <vector>
using boost::any_cast;
    
template <typename T, typename... Types> 
void Alert(T var1,Types... var2) 
{ 

    std::vector<boost::any> a(  {var1,var2...});

    for (int i = 0; i < a.size();i++)
    {

    if (a[i].type() == typeid(int))
    {
        std::cout << "int "  << boost::any_cast<int> (a[i]) << std::endl;
    }
    if (a[i].type() == typeid(double))
    {
        std::cout << "double "  << boost::any_cast<double> (a[i]) << std::endl;
    }
    if (a[i].type() == typeid(const char*))
    {
        std::cout << "char* " << boost::any_cast<const char*> (a[i]) <<std::endl;
    }
    // etc
    }

} 
       
    
void main()
{
    Alert("something",0,0,0.3);
}

Solution 17 - C++

We could also use an initializer_list if all arguments are const and of the same type

Solution 18 - C++

int fun(int n_args, ...) {
   int *p = &n_args; 
   int s = sizeof(int);
   p += s + s - 1;
   for(int i = 0; i < n_args; i++) {
     printf("A1 %d!\n", *p);
     p += 2;
   }
}

Plain version

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionnunosView Question on Stackoverflow
Solution 1 - C++Shafik YaghmourView Answer on Stackoverflow
Solution 2 - C++wilhelmtellView Answer on Stackoverflow
Solution 3 - C++YSCView Answer on Stackoverflow
Solution 4 - C++Markus ZancolòView Answer on Stackoverflow
Solution 5 - C++OmnifariousView Answer on Stackoverflow
Solution 6 - C++WillView Answer on Stackoverflow
Solution 7 - C++FrancescoView Answer on Stackoverflow
Solution 8 - C++Dave Van den EyndeView Answer on Stackoverflow
Solution 9 - C++ZoliView Answer on Stackoverflow
Solution 10 - C++KieveliView Answer on Stackoverflow
Solution 11 - C++kungfoomanView Answer on Stackoverflow
Solution 12 - C++OrifView Answer on Stackoverflow
Solution 13 - C++Dunya DegirmenciView Answer on Stackoverflow
Solution 14 - C++Thomas Padron-McCarthyView Answer on Stackoverflow
Solution 15 - C++ChrisView Answer on Stackoverflow
Solution 16 - C++AftershockView Answer on Stackoverflow
Solution 17 - C++pkumar0View Answer on Stackoverflow
Solution 18 - C++Вениамин РаскинView Answer on Stackoverflow