template<int N>
void f()
{
constexpr int n = 9;
++*const_cast<int*>(&n); // ok
++*const_cast<int*>(&N); // error C2101: '&' on constant
}
int main()
{
f<8>();
}
According to cppref :
the name of a variable, a function, a template parameter object (since C++20), or a data member, regardless of type, such as std::cin or std::endl. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;
Two questions:
1. Why does vc++ 2019 (with /std:c++latest) not accept the code?
2. Why does C++20 permit a template parameter object be an lvalue?
template parameter object is a normative term, that refers only to template parameters that have a class type.
temp.param/6 (emphasis mine)
...An id-expression naming a non-type template-parameter of class type T denotes a static storage duration object of type const T, known as a template parameter object , whose value is that of the corresponding template argument after it has been converted to the type of the template-parameter. All such template parameters in the program of the same type with the same value denote the same template parameter object. [ Note: If an id-expression names a non-type non-reference template-parameter, then it is a prvalue if it has non-class type. Otherwise, if it is of class type T, it is an lvalue and has type const T ([expr.prim.id.unqual]) . — end note ]
Since int
is not of a class type, it's not a template parameter object. We can consult the relevant section for the normative text on the value category here, which supports the note:
... The expression is an lvalue if the entity is a function, variable, structured binding ([dcl.struct.bind]), data member, or template parameter object and a prvalue otherwise ...
Since we are not in the "template parameter object" case, we are dealing with a prvalue, and as such may not apply unary &
to it, like any other prvalue.
Template parameters get replaced by the corresponding values at compile time. So N is no variable, but more like a macro. In you example you call f<8>() so the line ++*const_cast<int*>(&N);
will become ++*const_cast<int*>(&8);
And of course you can't take the address of 8.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.