Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does aggregate-initializing a non-type template parameter with a placeholder for a deduced class type fail to compile? [duplicate]

I was under the impression that the following should become valid code under the new C++20 standard:

struct Foo
{
  int a, b;
};

template<Foo>
struct Bar
{};

Bar<{.a=1, .b=2}> bar;

Yet, gcc 10.2.0, with -std=c++20 set complains: could not convert ‘{1, 2}’ from ‘<brace-enclosed initializer list>’ to ‘Foo’ and Clang cannot compile this snippet either. Can someone point out why it is not well formed?

like image 377
Peter Avatar asked Nov 05 '20 18:11

Peter


People also ask

What is a non-type template parameter?

A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument. A non-type parameter can be any of the following types: An integral type. An enumeration type. A pointer or reference to a class object.

What is a template template parameter in C++?

In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

Which is the correct example of template parameters?

For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.


2 Answers

This template-argument

{.a=1, .b=2}

is not allowed according to the grammar for a template-argument which only allows the following constructs:

template-argument:

constant-expression

type-id

id-expression

A brace-init list is not any of the above constructs, it's actually an initializer and so it cannot be used as a template-argument.

You can be explicit about the type of the object that you use as the template-argument:

Bar<Foo{.a=1, .b=2}> bar;

and this will work, since this is a constant-expression.

like image 190
cigien Avatar answered Sep 27 '22 17:09

cigien


It's a C++ grammar thing. Things used for template arguments must be either type-ids, id-names, or constant-expressions.

And a braced-init-list is not an expression of any kind. They can only grammatically be present in a small number of places, specifically those used to initialize an object or variable.

In the past, it wasn't really relevant, since there wasn't much reason to use a braced-init-list to initialize the few valid NTTPs. Obviously that's changed, so this is something of an oversight. But this is what the C++20 standard says.

like image 37
Nicol Bolas Avatar answered Sep 27 '22 19:09

Nicol Bolas