Class type non-type template parameter initialization does not compile
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?
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.
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.