Search code examples
c++gcccompiler-errorsinitializationctad

class template argument deduction failed on the use of designated initializers with list initialization


The compilers (GCC and Clang) are giving an error when using the curly braces init syntax with designated initializers when initializing a struct template instance.

Here:

template <class T>
struct Foo
{
    const T value;
};

int main( )
{
    Foo foo { .value = 5 };        // compiles
    // Foo foo { .value = { 5 } }; // does not compile
    // Foo foo { .value { 5 } };   // does not compile
}

The error message:

<source>: In function 'int main()':
<source>:11:30: error: class template argument deduction failed:
   11 |     Foo foo { .value = { 5 } };
      |    

What's causing this? Isn't list-initialization allowed in this context? Or something else is the root cause?


Solution

  • You're running into an interesting interaction between class template argument deduction and aggregate initialization. Normally, CTAD only happens using constructors/deduction guides, but for aggregate types, there is an additional aggregate deduction candidate.

    The compiler considers a hypothetical constructor made of all the aggregate elements. In this case, it is as if you declared a constructor

    Foo(T);
    

    The initializer of the designated initializer is then provided as an argument to this hypothetical constructor, attempting to deduce T as if it was a function template parameter. In other words, it is as if you had the following:

    template <typename T>
    void foo(T);
    
    // ...
    
    foo(5);    // { .value = 5 }
    foo({5});  // { .value = { 5 } } or { .value { 5 } }
    

    The first case (foo(5)) is valid, but foo({5}) is ill-formed because function template parameters cannot be deduced from initializer lists (see [temp.deduct.type] p5.7); it is one of the non-deduced contexts.