I discovered that using a template as the »type« of a non-type template parameter seems to be allowed since C 20:
template< typename T >
struct LiteralType {
T a, b, c;
};
template< LiteralType t >
struct S {
static constexpr auto value = t;
};
auto f() {
return S< LiteralType< int >{} >::value;
}
(see https://godbolt.org/z/KdTcY8rqo). Why exactly is this allowed?
Informally, every instantiation of LiteralType
is literal (or structural?) type, but where is this formally allowed in the standard?
Reading https://eel.is/c draft/temp.param#6 briefly, only types are allowed for non-type template-parameters, not templates.
CodePudding user response:
The paragraph you read says "a placeholder for a deduced class type". This is standard verbiage for allowing class template argument deduction. Since C 17, we can declare variables as follows
std::vector v{1, 2, 3};
The type of v
is deduced via CTAD from the initializer, and the template name serves as placeholder.
The C 20 code you show is just a natural extension of this. The non-type template parameter has its type deduced from the argument you provide as initializer (coincidently, even in C 17 we had deduction in this place, via auto
placeholder types).