This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 114a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-04-18


2318. Nondeduced contexts in deduction from a braced-init-list

Section: 13.10.3.6  [temp.deduct.type]     Status: CD5     Submitter: Jonathan Caves     Date: 2016-08-12

[Accepted as a DR at the February, 2019 meeting.]

The status of an example like the following is unclear:

  template<typename T, int N> void g(T (* const (&)[N])(T)) { }

  int f1(int);
  int f4(int);
  char f4(char);

  void f() {
    g({ &f1, &f4 });  // OK, T deduced to int, N deduced to 2?
  }

The problem is the interpretation of 13.10.3.6 [temp.deduct.type] paragraph 4:

In most cases, the types, templates, and non-type values that are used to compose P participate in template argument deduction. That is, they may be used to determine the value of a template argument, and the value so determined must be consistent with the values determined elsewhere. In certain contexts, however, the value does not participate in type deduction, but instead uses the values of template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.

According to 13.10.3.2 [temp.deduct.call] paragraph 1, deduction is performed independently for each element of the initializer list:

Template argument deduction is done by comparing each function template parameter type (call it P) that contains template-parameters that participate in template argument deduction 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'> or P'[[N] for some P' and N and the argument is a non-empty 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, 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 (13.10.3.6 [temp.deduct.type]).

Deduction fails for the second element of the list, &f4, because of ambiguity. Does this mean that deduction fails for the entire call, or does the successful deduction of T from the first element and N from the length of the list result in successful deduction for the call?

Notes from the July, 2017 meeting:

CWG determined that the call is well-formed.

Proposed resolution (November, 2018):

Change 13.10.3.2 [temp.deduct.call] paragraph 1 as follows:

Template argument deduction is done by comparing each function template parameter type (call it P) that contains template-parameters that participate in template argument deduction 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'> or P' [N] for some P" and N and the argument is a non-empty initializer list (9.4.5 [dcl.init.list]), then deduction is performed instead for each element of the initializer list independently, taking P' as a separate function template parameter types P'i and the i-th initializer element as its the corresponding argument. , and in 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 (13.10.3.6 [temp.deduct.type]). [Example:

  ...
  template<class T, int N> void n(T const(&)[N], T);
  n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3

  template<typename T, int N> void o(T (* const (&)[N])(T)) { }
  int f1(int);
  int f4(int);
  char f4(char);
  o({ &f1, &f4 }); // OK, T deduced as int from first element, nothing deduced from second element, N deduced as 2
  o({ &f1, static_cast<char(*)(char)>(&f4) }); // error: conflicting deductions for T