Consider the code:
class Base{};
class Derived: public Base{};
template<Base& b> // references (and pointers) can be used as non-types
void f(){}
int main()
{
Derived d;
// f(d); // Error, template type must match exactly
f<(Base&)d>(); // Error here, why?!
}
I understand why the commented call fails: the template type must match exactly. I try however a cast in the second call, and get this error (gcc5.2):
error: 'd' is not a valid template argument for type 'Base&' because it is not an object with external linkage
Same error if I make Derived d;
global. clang is a bit more helpful, saying
... note: candidate template ignored: invalid explicitly-specified argument for template parameter 'b'
My question is: is the code above legal or not? If not, are there any reasons why?
This answer assumes C++11 or higher
Two issues here:
1) No derived-to-base conversion for non-type template parameter [temp.arg.nontype]/p1
For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):
— a subobject (1.8),
2) The object's address should be available at compile time. Summarizing [temp.arg.nontype]/p1 and [expr.const]/p5 it follows that it should have static storage duration.
Put these two points together and you'll have that the following compiles
class Base{};
class Derived: public Base{};
template<Base& b> // references (and pointers) can be used as non-types
void f(){}
Base obj; // Static storage duration
int main()
{
f<obj>();
}
Live Example
From [temp.arg.nontype]:
A template-argument for a non-type template-parameter shall be a converted constant expression (5.20) of the type of the template-parameter.
There are two issues here. First, d
doesn't have linkage so you can't take a reference to it in a constant expression. That's an easy fix though:
Derived d;
int main() {
f<d>(); // still an error
}
Now, we have another issue. We move onto the next sentence:
For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):
(1.1) — a subobject (1.8),
We're trying to take a reference is a subobject (a base class subobject) of Derived
. That is explicitly disallowed, regardless of linkage.
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