Template argument deduction from an initializer list
Section [dcl.spec.auto]
Faisal Vali

Created on 2012-10-09.00:00:00 last changed 111 months ago


Date: 2015-04-13.00:00:00

Additional note, April, 2015:

EWG has decided not to make a change in this area. See EWG issue 109.

Date: 2012-10-15.00:00:00

Rationale (October, 2012):

CWG felt that this language design question would be better considered by EWG.

Date: 2022-11-20.07:54:16

An initializer list is treated differently in deducing the type of an auto specifier and in a function call. In [dcl.spec.auto] paragraph 6, an initializer list is given special treatment so that auto is deduced as a specialization of std::initializer_list:

Once the type of a declarator-id has been determined according to 9.3.4 [dcl.meaning], the type of the declared variable using the declarator-id is determined from the type of its initializer using the rules for template argument deduction. Let T be the type that has been determined for a variable identifier d. Obtain P from T by replacing the occurrences of auto with either a new invented type template parameter U or, if the initializer is a braced-init-list (9.4.5 [dcl.init.list]), with std::initializer_list<U>. The type deduced for the variable d is then the deduced A determined using the rules of template argument deduction from a function call ( [temp.deduct.call]), where P is a function template parameter type and the initializer for d is the corresponding argument.

In a function call, however, an initializer-list argument is a non-deduced context:

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<P'> for some P' and the argument is an initializer list (9.4.5 [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. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context ( [temp.deduct.type]). [Example:

  template<class T> void f(std::initializer_list<T>);
  f({1,2,3});          // T deduced to int
  f({1,"asdf"});       // error: T deduced to both int and const char*

  template<class T> void g(T);
  g({1,2,3});          // error: no argument deduced for T

This seems inconsistent, but it is not clear in which direction the inconsistency should be resolved. The use of an initializer list in a range-based for is an argument in favor of the [dcl.spec.auto] treatment, but the utility of this deduction in other contexts is not apparent.

Date User Action Args
2015-04-13 00:00:00adminsetmessages: + msg5431
2015-04-13 00:00:00adminsetstatus: extension -> nad
2012-11-03 00:00:00adminsetmessages: + msg4190
2012-10-09 00:00:00admincreate