Why didn't C ++ explicitly create template methods overriding virtual methods?

Why doesn't TemplateChild in the following code work? I know that virtual methods cannot be templates, but why do not explicitly created template methods override virtual methods?

#include <iostream> class VirtBase { public: VirtBase() {}; virtual ~VirtBase() {}; virtual void method( int input ) = 0; virtual void method( float input ) = 0; }; class RegularChild : public VirtBase { public: RegularChild() {}; ~RegularChild() {}; void method( int input ) { std::cout << "R" << input << std::endl; } void method( float input ) { std::cout << "R" << input << std::endl; } }; class TemplateBounceChild : public VirtBase { public: TemplateBounceChild() {}; ~TemplateBounceChild() {}; void method( int input ) { this->method<>( input ); } void method( float input ) { this->method<>( input ); } template< typename INPUT > void method( INPUT input ) { std::cout << "B" << input << std::endl; }; }; class TemplateChild : public VirtBase { public: TemplateChild() {}; ~TemplateChild() {}; template< typename INPUT > void method( INPUT input ) { std::cout << "T" << input << std::endl; }; }; template void TemplateChild::method< int >( int ); template void TemplateChild::method< float >( float ); int main( int, char**, char** ) { int i = 1; float f = 2.5f; VirtBase * v; RegularChild r; v = &r; r.method( i ); r.method( f ); v->method( i ); v->method( f ); TemplateChild c; // TemplateBounceChild here works correctly. v = &c; c.method( i ); c.method( f ); v->method( i ); v->method( f ); return 0; } 

gcc 4.4.7 (CentOS 6) and Clang 3.3 (trunk 177401) agree that two pure virtual methods are not implemented in TemplateChild, although at the moment in compilation TemplateChild explicitly has a method called "method" that accepts a float and a method named 'method' that takes an int.

Is it just because explicit instance creation is too late for TemplateChild to be considered unclean virtual?

Edit: C ++ 11 14.5.2 [temp.mem] / 4 says this is not allowed for specializations. But I cannot find anything so clear in the [temp.explicit] section for the same.

 4 A specialization of a member function template does not override a virtual function from a base class. 

I also edited TemplateBounceChild to fit the example used in this section of the C ++ 11 project.

+6
source share
3 answers

Because the standard says so. See C ++ 11 14.5.2 [temp.mem] / 3:

The member function template must not be virtual.

+3
source

Let's look at what happens if it is allowed.

The definition of the TemplateChild class can be present in several translation units (source files). In each of these translation units, the compiler must be able to generate a virtual function table (vtable) for TemplateChild to ensure that vtable is present to use the linker.

The vtable says: "for an object whose dynamic type is TemplateChild , these are the final overrides for all virtual functions." For example, for RegularChild vtable shows two overrides of RegularChild::method(int) and RegularChild::method(float) .

Your explicit instances for TemplateChild::method will only appear in one translation unit, and the compiler only knows that they exist in one translation unit. When compiling other translation units, he does not know that explicit instances exist. This means that you will end up with two different vtables for the class:

In the translation block, where explicit instances are present, you will get a vtable that displays two overrides of TemplateChild::method<int>(int) and TemplateChild::method<float>(float) . This is normal.

But in translation units, where there are no explicit instances, you will have a vtable that maps to the virtual functions of the base class (which in your example are purely virtual, just pretend that there are definitions of the base class).

You can even have more than two different vtables, for example. if explicit instances for int and float appear in their own translation unit.

In any case, we now have several different definitions for the same thing, which is a serious problem. In the best case, the linker can choose one and discard the rest. Even if there was some way to tell the linker to choose one that has explicit instances, you still have the problem that the compiler can devirtualize virtual function calls, but for that the compiler needs to know which final overrides (in fact , he should know that in vtable).

So, there are serious problems that would arise if this were resolved, and given the C ++ compilation model, I do not think that these problems are solvable (at least not without major changes in the way C ++ is compiled).

+7
source

Explicit instance creation no more than causes template creation. For a function template, this is the same effect as its use. There is no reason to expect that something will work differently, whether the member function is explicitly instantiated or used regularly.

Template specialization cannot override a function without a template because they do not have the same name. Specialization is called an identifier template, including template arguments. Ignoring template arguments in a signature, some specializations with different arguments may have the same signature.

If the language wanted to determine that specialization should be a virtual redefinition, since the signature matches the virtual member of the base class, it would have to determine that all template arguments could be inferred if the function was called with some arguments matching some virtual function. It will not be able to count on how you actually call the function (which looks like a virtual dispatch due to deduction), because you can call it in a more obscure way using template arguments or never call it at all (which is the problem, which you are trying to work with using an explicit instance).

The combination of functions N of the base class virtual and templates of classes M potentially corresponding to them will have complexity O (N * M). In this case, the special function will not scale well.

So, it’s better to just be explicit with the regular declaration of the virtual function to actually override. (It might be nice to be able to pseudonize such functions together so that their addresses are compared equal, although although pointers to virtual member functions work differently, identical functions can be micro-optimized.)

+4
source

All Articles