struct S{
constexpr S() {};
};
template <auto x> void f();
int main() {
S s{};
f<s>();
}
First off, per [temp.arg.nontype]/1
If the type T of a template-parameter (13.2) contains a placeholder type (9.2.9.6) or a placeholder for a deduced class type (9.2.9.7), the type of the parameter is the type deduced for the variable x in the invented declaration
T x = template-argument;If a deduced parameter type is not permitted for a template-parameter declaration (13.2), the program is ill-formed.
Our template parameter contains a placeholder type auto, so the type of the parameter is the type deduced for the variable x in the invented declaration auto x = s; In this case, the type of the parameter is S, and S is a permitted type for the parameter declaration because S is a structural literal type.
Second, per [temp.arg.nontype]/2
A template-argument for a non-type template-parameter shall be a converted constant expression (7.7) of the type of the template-parameter.
This means the template-argument s shall be a converted constant expression. So per [expr.const]/10:
A converted constant expression of type
Tis an expression, implicitly converted to typeT, where the converted expression is a constant expression and the implicit conversion sequence contains only
- [..]
- (10.2) — lvalue-to-rvalue conversions (7.3.2)
- [..]
I'm not sure whether or not the lvalue s is converted to prvalue before any implicit conversions are applied to it. Note the definition of converted constant expression in C++14 is relatively changed. N4140 §5.19 [expr.const]/3: (emphasis mine)
A converted constant expression of type
Tis an expression, implicitly converted to a prvalue of typeT, where the converted expression is a core constant expression and the implicit conversion sequence contains only [..]
So per C++14, It's guaranteed that the converted expression is converted to a prvalue before any implicit conversion is applied to it.
I'm not so sure whether or not an lvalue-to-rvalue conversion is applied to template-argument s. In other words, I'm not sure that the lvalue s is converted to a prvalue.
So in general, if I passed an lvalue as a template argument for a non-type template parameter, does an lvalue-to-rvalue conversion applied to that lvalue?
And aside from that, Is the object s constant-initialized?