Search code examples
c++c++14language-lawyertemplate-argument-deduction

Was the C++14 standard defective/underspecified w.r.t. deduction of an array type function parameter from an initializer list?


It comes as no surprise that the following program

// #1
template<typename T, std::size_t N>
void f(T (&&)[N]) {}

int main() { f({1,2,3}); }

is seemingly well-formed in C++14 (well, at least all compilers that I've tried seems to accepts it).

However, it seems as if this is not supported by the C++14 standard, particularly that T and N can be deduced from an initializer list argument?

[temp.deduct.type]/3.4

A given type P can be composed from a number of other types, templates, and non-type values:

  • [...]
  • /3.4 An array type includes the array element type and the value of the array bound.

explains why deduction succeeds for the following example:

template<typename T, std::size_t N>
void f(T (&)[N]) {}

int main() { 
    int arr[] = {1, 2, 3};  // #2
    f(arr);
}

where particularly [dcl.init.aggr]/4 governs that #2 declares and array of size 3 (even though omitted from the type in the declaration).

However, in the context of a function call, as per [temp.deduct.type]/5.6

A function parameter for which the associated argument is an initializer list ([dcl.init.list]) but the parameter does not have std::initializer_list or reference to possibly cv-qualified std::initializer_list type.

... this is a non-deduced context.

From the C++17 standard and onwards [temp.deduct.call]/1 has been updated to express that an array type argument can be deduced from a (non-empty) initializer list, but this was not present in the C++14 standard, and [temp.deduct.type]/5.6, regarding non-deduced contexts, explicitly refers to [temp.deduct.call]/1 for exceptions to the rule.

Was this a defect/underspecification of the C++14 standard?

  • If so, is there an associated defect report(1)?
  • If not, what passages of the C++14 standard covers that #1 above is well-formed?

(1) I've tried to find one myself without any success.


Solution

  • This is DR 1591.

    It would seem reasonable ... to allow an array bound to be deduced from the number of elements in the initializer list, e.g.,

      template<int N> void g(int const (&)[N]);
      void f() {
        g( { 1, 2, 3, 4 } );
      }
    

    Being a DR, it applies retroactively to C++14.


    NB: It seems Language Lawyer beat me to it, but I found it independently through git blame of templates.tex:)