Home c++ template virtual function

template virtual function

Author

Date

Category

Please explain why you can not create a virtual template function?

Found the following Explanation :

Member Function Templates Cannot Be Declared Virtual. This Constraint.
IS IMPOSED BECAUSE THE USUAL IMPLEMENTATION OF THE VIRTUAL FUNCTION
Call Mechanism Uses A Fixed-Size Table With One Entry Per Virtual
Function. HOWEVER, THE NUMBER OF INSTANTIATIONS OF A Member Function
Template IS Not Fixed Until The Entire Program Has Been Translated.
Hence, Supporting Virtual Member Function Templates Would Require
Support for a while new Kind of Mechanism in C++ Compilers and
Linkers. IN CONTRAST, THE ORDINARY MEMBERS OF CLASS TEMPLATES CAN BE
Virtual Because Their Number Is Instantiated

Virtual Because

That is, you can implement theoretically such functionality, but it will require a serious change in the principles of the existing compiler and linkers. Or are there other reasons?


Answer 1, Authority 100%

Simply answer:

in C++ function pattern is not a function, so the template cannot be virtual.

in C # / Java / etc are not used templates, but generics. Generic function is (one) function, so there is no such problem there.

Complete answer:

in C++ Virtual functions are made so that their number is written in the definition of the basic class.
This allows you to assign the functions of some index in the base class and quickly find it in this index.

struct base {
 FUNC_T * VFT; // Hidden Class Member - An array of virtual functions
 Virtual Void F ();
};
Base * x = new derived;
x- & gt; f ();
// Compiled B.
X- & GT; VFT [0] ();

If templates are virtual, then instead of enumerating functions in the base class, you need to search for all settings of the template when the function is called.
To do this, instead of indexes, you need to use names, and search for these names in the hash table.

struct base {
 hash_map & lt; string, func_t & gt; VFT; // Hidden Class Member - High Table Virtual Functions
 TEMPLATE & LT; TYPENAME T & GT; Virtual Void F ();
};
Base * x = new derived;
x- & gt; f & lt; int & gt; ();
// Compiled B.
X- & GT; VFT ["F & LT; INT & GT;"] ();

Call speed will significantly fall, because It will be necessary to resolve collisions.

You can use the perfect hash function (without collisions).

struct base {
 FUNC_T * VFT; // Hidden Class Member - Array (SIC!) Virtual functions
 Virtual Void F ();
};
Base * x = new derived;
x- & gt; f ();
// Compiled B.
X- & GT; VFT [ideal_hash ("f & lt; int & gt;")] ();
// IDEAL_HASH (Name) gives the array index, without conflicts

But due to dynamic links (.so / .dll) the entire source code of the program is not available, and with each SO / DLL download, you need to stop the entire program, change the hash function and rebuilding all the tables to take into account the types that were added to This SO / DLL.


Using Jit compiler can replace virtual calls to normal, and then no problem with the call capacity will not be.

// instead of x- & gt; f (); Generated
X- & GT; DERIED :: F ();
// If it is proved that there can be only derived

But devotyatualization works only if the number of classes is not enough, and at the moment there are no effective JIT compilers. (Those that are, for example, in LLVM, do not show good results.)


Answer 2, Authority 67%

It is impossible to be done within the framework of existing C++ implementations. Since virtual functions are implemented via the tables of pointers on them, the compiler must be able to generate a function when it is determined – to get a pointer.

Since the code of template functions is generated only when instantiating the template, the compiler cannot fill in the table – it simply does not have a pointer.

The template virtual functions would require a complete revision of the approach to polymorphism, and for complete implementation would require a “executing machine” – approximately as Java or C #.

simple example (not compiled, naturally):

// File Base.h
STRUCT BASE {
  TEMPLATE & LT; Class T & GT;
  Virtual Void Foo (T) {}
};
// File Derived.h.
#Include & lt; base.h & gt;
STRUCT DERIVED: BASE {
  TEMPLATE & LT; Class T & GT;
  Virtual Void Foo (T) {};
};
// File Foo.CPP
#Include & lt; base.h & gt;
Void Foo (Base * B) {
  Base- & gt; foo (42);
}
// File Main.CPP.
#Include & lt; derived.h & gt;
INT MAIN () {
  Base * d = new derived;
  Foo (D);
}

In the example above, it is obvious that the compiler cannot form the correct call to the foo () function .

In the comments, such an argument is given – “And let’s force the user to include all the headers of all descendants before using the template function, and the compiler generate all the tables of virtual methods for the entire Base tree that he saw in-place. But the foo () pointer already should be formed table. It will not be possible to reform it!

Programmers, Start Your Engines!

Why spend time searching for the correct question and then entering your answer when you can find it in a second? That's what CompuTicket is all about! Here you'll find thousands of questions and answers from hundreds of computer languages.

Recent questions