Error when explicitly converting a custom template parameter

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 type of the template must match exactly. I am trying to throw 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 connection

Same error if I do Derived d; global clang is a little more useful saying

... note: candidate template is ignored: invalid explicit argument for template parameter 'b'

My question is: is the code above legal or not? If not, are there any reasons?

+5
source share
2 answers

This answer assumes C ++ 11 or higher.

Two questions here:

1) There are no base-based conversions for the non-pig type template parameter [temp.arg.nontype] / p1

For a template-template that is not related to the type of the link or the type of the pointer, the value of the constant expression should not refer to (or for the type of the pointer, there should be no address):

- subobject (1.8),

2) The address of the object must be available at compile time. Summing up [temp.arg.nontype] / p1 and [expr.const] / p5, it follows that it should have a static storage duration .

Connect these two points and you will get the following compilations

 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>(); } 

Living example

+4
source

From [temp.arg.nontype]:

The template argument for a non-type template parameter must be a constant constant expression (5.20) of the type of the template parameter.

There are two problems here. Firstly, d has no binding, so you cannot refer to it in a constant expression. This is easy to fix, though:

 Derived d; int main() { f<d>(); // still an error } 

Now we have one more problem. Let's move on to the following sentence:

For a template-template that is not related to the type of the link or the type of the pointer, the value of the constant expression should not be referenced (or for the type of the pointer, there should be no address):
(1.1) is the subobject (1.8),

We are trying to take a link - this is a subobject (subobject of the base class) Derived . This is explicitly prohibited, regardless of binding.

+2
source

Source: https://habr.com/ru/post/1232300/


All Articles