Consider a simple example:
int x;
template <template <auto> class TT>
struct Foo {
void foo() {
TT<(x)> tt;
static_cast<void>(tt);
}
};
template <decltype(auto)>
struct Bar { };
int main() {
Foo<Bar> foobar;
foobar.foo();
}
[clang] seems to deal with the idea of decltype(auto)
placeholder despite the use of auto
in template template parameter declaration without a problem.
[gcc] on the other hand - not very well:
prog.cc:6:13: error: the value of 'x' is not usable in a constant expression
As usually - which behaviour is expected according to standard? Or maybe everything is possible and the code is ill-formed (this time I suppose not but cannot rule it out definitively)?
PS. Sorry for breaking one of the compilers again ;)
Which parameter is legal for non-type template? Explanation: The following are legal for non-type template parameters:integral or enumeration type, Pointer to object or pointer to function, Reference to object or reference to function, Pointer to member.
A non-type template argument provided within a template argument list is an expression whose value can be determined at compile time. Such arguments must be constant expressions, addresses of functions or objects with external linkage, or addresses of static class members.
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.
Templates can be template parameters. In this case, they are called template parameters. The container adaptors std::stack, std::queue, and std::priority_queue use per default a std::deque to hold their arguments, but you can use a different container.
The original answer here had Foo<Bar>
ill-formed, I actually now think it's well-formed. But ultimately, clang bug based.
I actually think even The new rules, following P0522 are that:Foo<Bar>
is ill-formed.
A template-argument matches a template template-parameter
P
whenP
is at least as specialized as the template-argumentA
where:
A template template-parameter
P
is at least as specialized as a template template-argumentA
if, given the following rewrite to two function templates, the function template corresponding toP
is at least as specialized as the function template corresponding toA
according to the partial ordering rules for function templates ([temp.func.order]). Given an invented class templateX
with the template parameter list ofA
(including default arguments):
- Each of the two function templates has the same template parameters, respectively, as
P
orA
.- Each function template has a single function parameter whose type is a specialization of
X
with template arguments corresponding to the template parameters from the respective function template where, for each template parameterPP
in the template parameter list of the function template, a corresponding template argumentAA
is formed. IfPP
declares a parameter pack, thenAA
is the pack expansionPP...
([temp.variadic]); otherwise,AA
is the id-expressionPP
.If the rewrite produces an invalid type, then
P
is not at least as specialized asA
.
Which means that to verify if Foo<Bar>
itself is okay, we synthesize:
template <decltype(auto) I> struct X;
template <auto I> void __f(X<I> ); // P
template <decltype(auto) I> void __f(X<I> ); // A
All the types here are valid (so the last statement doesn't apply). Now, typically when we do partial ordering it's in the context of either overload resolution or picking a class template specialization, in which case what we're looking for is the "more specialized" function template, where F
is more specialized than G
if F
is at least as specialized as G
and G
is not at least as specialized as F
.
But in this context, we don't care about which is more specialized. We only need P
to be at least as specialized as A
. All that means that deduction has to succeed from A
to P
. So if we synthesize some unique type U
with some value V
, can we deduce X<I>
from X<V>
? Yes. Hence, P
is at least as specialized as A
, so the template-argument Bar
matches the template-parameter TT
.
Now, passing that point, I'd say this a clang bug. The template template-parameter is template <auto>
, which is what we should use to validate the expression. With a non-type template parameter auto
, we'd try to use x
as a value - but x
isn't a valid constant expression, so this should fail. clang appears to be using template <decltype(auto) >
directly - which I'm not sure is valid.
That said, I'm not sure this case has even been considered - I don't see any wording one way or the other and it's worth raising an issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With