Problem with calling a variadic function template when passing brace initialiser list arguments

  • A+
Category:Languages

Consider this function template:

template <class... T> void foo (std::tuple<T, char, double> ... x); 

This invocation works:

using K = std::tuple<int, char, double>; foo ( K{1,'2',3.0}, K{4,'5',6.0}, K{7,'8',9.0} ); 

This one doesn't:

foo ( {1,'2',3.0}, {4,'5',6.0}, {7,'8',9.0} ); 

(gcc and clang both complain about too many arguments for foo)

Why is the second call a problem? Can I rewrite the declaration of foo so that the second call is also accepted?

Thee template parameter T is only used to implement variadicity. The actual type is known and fixed, only the number of arguments varies. In real life the types are different from int, char, double, this is just an example.

I cannot use C++17 for this. A C++11-compatible solution is much preferred.

 


{} is not an expression hence don't have type, argument deduction is concerned about types, special care is taken when the argument used to perform argument deduction is an initializer list the template function parameter must have specifics forms, otherwise the parameter is a non-deduced context. A more simplistic example is this:

template <class T> struct A { T r; }; template <class T> void foo (A<T> x);  using K = A<int>; foo({1}); // fail foo(K{1}); // compile 

This is covered by [temp.deduc.call]/1

If removing references and cv-qualifiers from P gives std::initializer_­list<P'> or P'[N] for some P' and N and the argument is a non-empty initializer list ([dcl.init.list]), then deduction is performed instead for each element of the initializer list, taking P' as a function template parameter type and the initializer element as its argument, and in the P'[N] case, if N is a non-type template parameter, N is deduced from the length of the initializer list. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context

and [temp.deduct.type]/5

The non-deduced contexts are:

(5.6) A function parameter for which the associated argument is an initializer list ([dcl.init.list]) but the parameter does not have a type for which deduction from an initializer list is specified ([temp.deduct.call]).

When you:

  • explicitly provide template arguments, it works ... nothing to deduce
  • specify the argument as K{1}, it works ... the argument is not longer an initializer list, is an expression with type.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: