Multiple input with a function [duplicate] - c++

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

In C++11 you have two new options, as the 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 std::initializer_list would be std::vector or one of the other 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 variadic functions although they are not type-safe and in general 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 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. [...]

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.

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:
Variadic templates, also known as parameter pack Parameter pack(since C++11) - cppreference.com.
Fold expressions fold expression(since C++17) - cppreference.com.
See a full program demonstration on coliru.

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!

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.

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).

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++ ...

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.

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.

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

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.

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

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

// 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.

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

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

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

Related

Is base case function mandatory or could it be automatically synthesized?

In the following code :
void print()
{
// This is our base case fn
;; // Do nothing
}
template <typename type1, typename... argspack>
void print(type1 a, argspack... args_rest)
{
cout << a << ((sizeof...(args_rest) != 0) ? "," : "\n");
print(args_rest...); // I guess this recursive call is inevitable
}
If the recursive call to variadic function is inevitable, the base case function is also inevitable. If so, is there a language feature, perhaps one
that comes with modern c++, that help a programmer get away without writing a base case function?
Another (slightly elaborate) way which avoids recursion and a trailing comma:
#include <iostream>
#include <tuple>
struct linefeed {};
template<typename...Args>
void print(Args&&... args)
{
const char* sep = "";
auto print_with_sep = [&sep](auto& os, auto& arg)
{
if constexpr (std::is_same<std::decay_t<decltype(arg)>, linefeed>())
{
sep = "";
os << '\n';
}
else
{
os << sep << arg;
sep = ",";
}
};
auto print_all = [&](auto&&...things)
{
(print_with_sep(std::cout, things), ...);
};
print_all(args..., linefeed());
}
int main()
{
print(1,2,3,4,5, "hello");
print("world", 5,4,3,2,1);
}
expected output:
1,2,3,4,5,hello
world,5,4,3,2,1
https://coliru.stacked-crooked.com/a/770912eee67d04ac
A dummy is one way. Another is to make it a single argument function that actually does work:
template<typename T>
void print(T a)
{
std::cout << a;
}
template <typename type1, typename... argspack>
void print(type1 a, argspack... args_rest)
{
print(a);
std::cout << ((sizeof...(args_rest) != 0) ? "," : "\n");
print(args_rest...); // I guess this recursive call is inevitable
}
A benefit to this approach is that it provides a customization point too. If some type wants to provide its own print implementation, all it has to do is write the overload. ADL will find it and overload resolution will favor it.
To be perfectly clear, you have to write the base case yourself. The language doesn't consider those two functions as related beyond being overloads of the same name. It isn't even aware there needs to be a base case, that is our logical requirement.
You may refer to Fold Expression which is supported as of C++17.
I came up with the code almost similar to your code but it has a trailing comma.
template<typename... argspack>
void print(argspack&&... args) {
((cout << args << ","), ...) << "\n";
}
I am not sure there is a way to get exactly the same with your code using Fold Expression. Since we sizeof...(args) is always the initial size in this version.
With one function in C++11:
template <typename... Ts>
void print(Ts... args)
{
const char* sep = "";
const int dummy[] = {((std::cout << sep << args), (sep = ", "), 0)..., 0};
static_cast<void>(dummy); // Avoid warning for unused variable
std::cout << "\n";
}
dummy array trick can be replaced by fold expression in C++17:
template <typename... Ts>
void print(Ts... args)
{
const char* sep = "";
(((std::cout << sep << args), (sep = ", ")), ...);
std::cout << "\n";
}

printf like utility in c++ without format specifier?

I am trying to write a function that can convert its argument into a string. However, I am finding it difficult to unpack the parameter pack.
Here is the code that I have written:
#include <iostream>
#include <sstream>
template <typename... T>
std::string StringFormatter(T... values)
{
std::ostringstream out;
for (auto&& x : { values... }) {
out << x;
}
return out.str();
}
int main()
{
auto&& i = StringFormatter("One ", "two"); //Success
auto&& j = StringFormatter("one ", 1, "two", 2.0); //Fails
std::cout << i;
}
I know that the above code is failing because the initializer list accepts only single type arguments.
I have tried a recursive approach to achieve the above implementation, but no luck.
If you can suggest a better way to achieve this, it would be a great help.
You can achieve this with C++17's fold expression:
template <typename... T>
std::string StringFormatter(T... values)
{
std::ostringstream out;
(out << ... << values);
return out.str();
}
In short:
If you don't have a C++17 compiler, you can rely on the int array trick:
template <typename... T>
std::string StringFormatter(T... values) {
std::ostringstream out;
int arr[] = { 0, (out << values, void(), 0)... };
return out.str();
}
The apparently useless 0 at the start of the array is required in the case the parameter pack is empty because you can't instantiate an array of size 0. The void() is there to circumvent hypothetical operator, overloads.
The evaluation order is guaranteed and the compiler should be able to optimize away the array in the resulting binary.
In depth:
This technique is the pre-C++17 way of doing fold expressions. Basically we create an array of sizeof...(T) + 1 elements (all 0). The catch here is that we are using properties of the , operator to run the operation we want on each element of the parameter pack.
Let's forget about the parameter pack and the template for a moment.
When you do:
something, other_thing
Assuming there is no overload to the , operator, the statement is evaluated to other_thing. But that doesn't mean that something is ignored. Its value is just discarded in favor of other_thing. We are using that property for our little trick.
int x = 0;
int a[] = { 0, (++x, 0) }; // a is {0, 0}, x is 1
Now since you can overload operator,, we just add an additional statement to avoid this hypothetical overload:
(something, void(), 0)
Since operator, is a binary operator, an overloaded version of it cannot have only one argument. By adding a statement evaluating to void we are preventing any hypothetical overload to be picked and therefore are sure we end up with our 0.
The last step is to combine that with our parameter pack and perform pack expansion on the resulting statement:
(out << values, void(), 0)...
There are better ways to do it now (with a fold expression), but if you want to use the recursive approach, it can look something like this:
#include <sstream>
#include <string>
#include <iostream>
template <class T>
std::string stringify(T const &t) {
std::stringstream b;
b << t;
return b.str();
}
template<typename T, typename... Args>
std::string stringify(T arg, const Args&... args) {
return stringify(arg) + stringify(args...);
}
int main() {
std::string three{" three"};
std::cout << stringify("one: ", 1, " two: ", 2, three, "\n");
return 0;
}
You should be able to use this with essentially any type that supports stream insertion. If you're passing enough parameters that the quadratic time on the number of parameters is a concern, 1) go see a psychiatrist, and 2) feel free to use code more on this general order:
#include <sstream>
#include <string>
#include <iostream>
namespace detail {
template <class T>
void stringify(std::ostringstream &b, T const &t) {
b << t;
}
template<typename T, typename... Args>
void stringify(std::ostringstream &os, T arg, const Args&... args) {
stringify(os, arg);
stringify(os, args...);
}
}
template <typename ...Args>
std::string stringify(const Args &...args) {
std::ostringstream os;
detail::stringify(os, args...);
return os.str();
}
int main() {
std::string three{" three"};
std::cout << stringify("one: ", 1, " two: ", 2, three, "\n");
}
...but definitely see a psychiatrist first. If you're passing enough arguments for it to matter, you're clearly doing something horribly wrong.

How do I implement a variadic template that reads user input into all variables supplied?

I am currently trying to teach myself variadic templates. However I am having trouble understanding anything past a simple adding template.
Currently I would want a template that would do the following:
Take any number of types
Takes parameters that requires the user to enter them in the following format:
T value, string descriptor
It then goes through each variable one by one, printing the descriptor before reading the variable
For example the output should look like this:
x (int) //this is the descriptor
//here something is being read into the variable x
y (int) //this is another descriptor
//something else is being read into y
.
.
.
Since its always the same operation, this should be possible. However my best try looked like this
template<typename t,typename... Args>
void generic_reader(t first,string desc,Args... args)
{
cout<<desc<<endl;
cin>>first;
generic_reader(args);
}
Obviously this doesnt work. However I cant think of another way of doing this. Again I have only started to work with variadic templates.
Can someone show me a solution with a detailed explanation?
Here's one way, using recursion.
#include <iostream>
// provide a terminating case
void generic_read()
{
}
// provide the general case which picks off the first 2 arguments
// and forwards the rest to another version of itself.
template<typename T, typename Printable, typename...Rest>
void generic_read(T& value ,Printable&& desc,Rest&&...rest)
{
std::cout << desc << std::endl;
std::cin >> value;
generic_read(std::forward<Rest>(rest)...);
}
// test
int main()
{
int x;
double y;
generic_read(x, "an integer:", y, "a double");
}
You're basically there -- you're just missing a base case. Also, you're missing the ... on your recursive call to generic_reader; it should be generic_reader(args...).
Here's some working code that does what you're trying to do:
#include <string>
#include <iostream>
void generic_reader()
{
std::cout << "no more stuff!" << std::endl;
}
template <typename T, typename... Args>
void generic_reader(T& first, const std::string& desc, Args&... args)
{
std::cout << desc << std::endl;
std::cin >> first;
std::cin.ignore(100, '\n');
generic_reader(args...);
}
int main()
{
int x, y, z;
generic_reader(x, "x", y, "y", z, "z");
std::cout << "x: " << x << " y: " << y << " z: " << z << std::endl;
return 0;
}
`
Walking through the code: your approach was correct, but there's no base case when you run out of arguments. On the second to last call, the remaining arguments are (z, "z"), which substitutes into the template successfully. But after that, there is a final call to generic_reader(), with no remaining arguments. You need to provide a candidate that can accept the final (empty) argument list.
One final note -- you'll notice that I passed in first by reference, so I could write to the original variables. If you do this, make sure that the remaining Args... is passed by reference as well! Otherwise, recursive calls will pass the remaining args by value, and calls after the first one will no longer reference the original variables.
It seems to me that you're using a sequence of std::pairs where the first type is fixed, std::string, and the second one is a variable type.
So you can write your function as
template <typename ... Args>
void generic_reader (std::pair<std::string, Args> & ... ps)
{ /* do something */}
and call it as
auto a = std::make_pair<std::string>("a", short(0));
auto b = std::make_pair<std::string>("b", 1);
auto c = std::make_pair<std::string>("c", 2L);
auto d = std::make_pair<std::string>("d", 3LL);
generic_reader(a, b, c, d);
Unfortunately I don't know (before c++17) how to use ps... in the body of the function so, in C++11 and in C++17, the best I can think is a solution based on recursion (as your original, with the recursion call corrected in generic_reader(args...);)
Starting from C++17 it's available a new (and more powerful) mode of use variadic arguments (look for "fold expression") and your function ca be simply written as
template <typename ... Args>
void generic_reader (std::pair<std::string, Args> & ... ps)
{ ( (std::cout << ps.first << std::endl, std::cin >> ps.second), ... ) ; }
The following is a full working C++17 example
#include <utility>
#include <iostream>
template <typename ... Args>
void generic_reader (std::pair<std::string, Args> & ... ps)
{ ( (std::cout << ps.first << std::endl, std::cin >> ps.second), ... ) ; }
template <typename ... Args>
void variadic_printer (Args & ... as)
{ ( (std::cout << as.first << ", " << as.second << std::endl), ... ) ; }
int main ()
{
auto a = std::make_pair<std::string>("a", short(0));
auto b = std::make_pair<std::string>("b", 1);
auto c = std::make_pair<std::string>("c", 2L);
auto d = std::make_pair<std::string>("d", 3LL);
generic_reader(a, b, c, d);
variadic_printer(a, b, c, d);
}
If you prefer not to use recursion you can always use this (c++14, but there exist implementations of index_sequence for c++11):
#include <utility>
#include <iostream>
#include <tuple>
template <class Tuple, std::size_t... Is>
void generic_reader_impl(std::index_sequence<Is...>, Tuple&& tuple) {
std::size_t dummy[] = { 0ul,
(static_cast<void>(std::cout << std::get<2ul*Is + 1ul>(tuple) << std::endl),
static_cast<void>(std::cin >> std::get<2ul*Is>(tuple)),
Is)...
};
static_cast<void>(dummy);
}
template <class... Args>
void generic_reader(Args&&... args) {
generic_reader_impl(std::make_index_sequence<sizeof...(Args) / 2>{}, std::forward_as_tuple(std::forward<Args>(args)...));
}
int main() {
int x;
double y;
generic_reader(x, "an integer:", y, "a double");
std::cout << x << std::endl;
std::cout << y << std::endl;
}
Output:
1
1.2
[live demo]

Parameter pack expansion within parentheses gives bizarre output

I am trying to implement a function which accepts a variable number of strings and forwards to a print function, which expects a char pointer and size for every string, interleaved.
Example:
std::string a = "123";
std::string b = "1234";
forward(a, b); // should call doPrint(a.c_str(), a.size(), b.c_str(), b.size())
I thought that the following should be a correct implementation, but even though it compiles the behavior is very surprising to me.
template <class ...Args>
void forward(const Args & ... args) {
doPrint( (args.c_str(), args.size())...);
}
forward(a, b) calls doPrint(3, 4), and not doPrint("123", 3, "1234", 4), as if I had written doPrint((args.size())...). The call to c_str() is ignored completely by the compiler.
I tried g++, clang, and icc with all yielding the same output. What is wrong with (args.c_str(), args.size())...?
Indeed, std::make_tuple(args.c_str(), args.size())... works as expected, but let's say I cannot change doPrint to accept and process tuples.
The comma operator is an expression whose value is the value of the last expression.
For example:
int a = (1, 2, 3, 4, 5, 6);
assert(a == 6);
What you can try instead is using tuples:
doPrint(std::tuple_cat(std::make_tuple(argc.c_str(), args.size())...));
Then doPrint will need to be changed to work with a tuple; it could unpack the tuple back into a parameter pack if desired or just work with the tuple directly.
Example unpacking tuple:
template <class Tuple, std::size_t ... indices>
doPrint(Tuple t, std::integer_sequence<size_t, indices...>)
{
doPrint(std::get<indices>(t)...);
}
template <class Tuple>
doPrint(Tuple t)
{
doPrint(t, std::make_index_sequence<std::tuple_size<Tuple>::value>());
}
There could be some problems with ambiguous function names so you may need to change the names of these helper functions, but hopefully this is enough for you to get going.
(args.c_str(), args.size()) is a comma-separated expression, meaning that only the last part (args.size()) will be passed to the function.
It will then repeat this for each parameter, so it will actually call doPrint just with the strings sizes!
You should change doPrint to use tuples instead, otherwise you have to use some crazy template meta-programming stuff.
I'd probably do it this way in order to avoid exposing tuples to the programming interface:
#include <string>
#include <utility>
#include <tuple>
extern void doPrint(...);
namespace detail {
template<std::size_t...Is, class Tuple>
void forward(std::index_sequence<Is...>, Tuple&& tuple)
{
doPrint(std::get<Is>(tuple)...);
}
}
template<class...Strings>
void forward(Strings&&... strings)
{
detail::forward(std::make_index_sequence<sizeof...(Strings) * 2>(),
std::tuple_cat(std::make_tuple(strings.data(), strings.size())...)
);
}
int main()
{
std::string a = "123";
std::string b = "1234";
forward(a, b); // should call doPrint(a.c_str(), a.size(), b.c_str(), b.size())
}
Jason Turner demonstrates a concise way to expand variadic templates using an initializer list in this video:
http://articles.emptycrate.com/2016/05/09/variadic_expansion_wrap_up.html
template< typename ... T >
void do_print(T ... args)
{
(void)std::initializer_list<int> {
(std::cout << args.c_str() << ": "
<< args.size() << "\n", 0)...
};
}
template< typename ... T >
void forward_print(T ... args)
{
do_print(args...);
}
int main(int argc, const char * argv[])
{
std::cout << "Hello, World!\n";
std::string a = "1234";
std::string b = "567";
forward_print(a, b);
return 0;
}
This works with g++ -std=c++11

How does this variable argument notation work?

In C++ I can define a function with a variable number of arguments like this:
void a(int a...) {
std::cout << a << std::endl;
}
And call it like this:
a(100, 200, 300);
However, apparently I can only access the first argument: The output of the call is 100.
How do I access the other arguments with this notation?
Your syntax is ... unfortunate, and refers to a C-style vararg function.
In C++11 you should prefer variardic templates. The easiest approach is something like this:
First, some helper code:
#include <utility>
template<typename Lambda>
void for_each_arg( Lambda&& unused ) {}
template<typename Lambda, typename Arg1, typename... Args>
void for_each_arg( Lambda&& closure, Arg1&& arg1, Args&&... args ) {
closure( std::forward<Arg1>(arg1) );
for_each_arg( std::forward<Lambda>(closure), std::forward<Args>(args)... );
}
now, we use it:
#include <iostream>
template<typename... Args>
void foo( Args&&... args ) {
for_each_arg( [](int x){
std::cout << x << "\n";
}, std::forward<Args>(args)... );
}
int main() {
foo( 1, 2, 3 );
}
and we can access each argument, and ensure that they convert to int. Note that the conversion to int is deferred until call of the body of for_each_arg.
If you use a var args interface you need to be able to tell from the named parameters how many arguments where provided in total. For example, the <stdio.h> function do that by having the format string be the last named argument followed by as many arguments as specified in the argument list. To access the arguments you need to use the various va_... functions and types.
You are much better off using variadic templates:
template <typename... T>
void f(T... a) {
// just expand the parameter pack over here
}
Sample code using your function a:
#include <iostream>
#include <cstdarg>
void a(int a...)
{
va_list args;
va_start(args, a);
int b = va_arg(args, int);
int c = va_arg(args, int);
std::cout << a << ", " << b << ", " << c << std::endl;
}
int main()
{
a(100, 200, 300);
return 0;
}
The variable argument syntax does not know the number or type of the parameters. Therefore something in the parameter list must indicate the number and possibly the type of the parameters. There are several methods that are typically used to determine the number of parameters:
The first parameter is the number of parameters.
The last parameter is a delimiter, a NULL or other unique value, for example.
The first parameter has other embedded information that determines the number, order and type of the parameters, for example the format parameter for printf.
In this example, I've simply assumed there are three parameters. Calling a with more or less parameters will cause undefined behavior (read, random results, to a crash).
Another variadic solution:
template<typename T, typename... Vs>
void print(T&& t, Vs&&... vs) {
std::cout << std::forward<T>(t) << std::endl;
int sink[] { (std::cout << " " << std::forward<Vs>(vs) << std::endl, 0)... };
(void)sink; // silence "unused variable" warning
}
Which has the benefit of not requiring helpers. We use pack expansion to forward each argument one at a time to cout. For syntax reasons, I leverage the comma operator so that the expression (cout..stuff.., 0) resolves to an integer, which we then discard into an array; this lets us use the pack expansion operator around our complex statement.
A solution which enforces the type int.
But with a usage a little different
#include <initializer_list>
#include <iostream>
// Or you may use std::vector
void print(const std::initializer_list<int>& a) {
for (auto elem : a) {
std::cout << elem << std::endl;
}
}
int main(int argc, char *argv[])
{
print({1, 2, 3}); // extra braces.
return 0;
}