Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Having trouble passing multiple initializer lists to variadic function template

I don't understand the error message when trying to pass a variable number of initializer lists:

template<typename... Values>
void foo(Values...)
{
}

int main()
{
    foo(1, 2, 3, "hello", 'a');   // OK

    foo({1}, {2, 3});             // ERROR
}

The error message complains about too many arguments:

prog.cpp: In function ‘int main()’:
prog.cpp:9:20: error: too many arguments to function
                      ‘void foo(Values ...) [with Values = {}]’
     foo({1}, {2, 3});
                    ^
prog.cpp:2:6: note: declared here
 void foo(Values...)
      ^

However, should I not be able to pass as many arguments as I want? [ideone link]

like image 496
fredoverflow Avatar asked Nov 18 '13 22:11

fredoverflow


People also ask

What is Variadic template in C++?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration.

What is the use of Variadic templates?

With the variadic templates feature, you can define class or function templates that have any number (including zero) of parameters. To achieve this goal, this feature introduces a kind of parameter called parameter pack to represent a list of zero or more parameters for templates.

What is std :: Initializer_list?

An object of type std::initializer_list<T> is a lightweight proxy object that provides access to an array of objects of type const T .

What is parameter pack in c++?

Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.


2 Answers

The problem is likely deducibility. {} could be uniform initializers to any of the arguments.

This works:

#include <initializer_list>

template<typename... Values>
void foo(std::initializer_list<Values>... args)
{
}

template<typename... Values>
void foo(Values&&... args)
{
}

int main()
{    
    foo(1, 2, 3, "hello", 'a');
    foo({1}, {2, 3});
}

See it Live on Coliru

like image 180
sehe Avatar answered Oct 18 '22 18:10

sehe


The issue is not with the varadic arguments, but that the compiler cannot deduce the type of a brace enclosed initializer list, except for the case where you've declare the parameter of std::initializer_list<T>

§ 14.8.2.1 Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below. If removing references and cv-qualifiers from P gives std::initializer_list for some P0 and the argument is an initializer list (8.5.4), then deduction is performed instead for each element of the initializer list, taking P0 as a function template parameter type and the initializer element as its argument. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context (14.8.2.5).

There's even an example right below

template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T
like image 7
Dave S Avatar answered Oct 18 '22 19:10

Dave S