views:

637

answers:

5

I heard, templated member functions of a class can't be virtual. Is it true? BTW, if they can be, then please give an example of such a scenario when I would need such function?

+6  A: 

Think about it for a while:

Q.1. How could you make a templated virtual function?
Q.2. What's its signature?
Q.3. How many vtable entries do you reserve?
Q.4. How would you distinguish between an override/hide and an overload?

Hope that helps.

Rajendra Kumar Uppal
Can you please tell me a scenario where we need such function if this feature would have been supported?
WannaBeGeek
@WannaBeGeek: any situation in which you want runtime polymorphism on the first argument and at the same time generic code on another argument (i.e. Visitor pattern with generic implementations at each level, using dynamic runtime information to select an instance of a class and yet at each level you would want to support unrelated arguments in a similar way...)
David Rodríguez - dribeas
+1  A: 

No template member functions cannot be virtual.

dirkgently
My curiosity is: Why? What problems does the compiler faces in doing so?
WannaBeGeek
You need a declaration in scope (at least, in order to get the types correct). It is required by the standard (and the language) to have a declaration in scope for identifiers you use.
dirkgently
+9  A: 

Templates are all about the compiler generating code at compile-time. Virtual functions are all about the run-time system figuring out which function to call at run-time.

Once the run-time system figured out it would need to call a templatized virtual function, compilation is all done and the compiler cannot generate the appropriate instance anymore. Therefor, you cannot have virtual member function templates.

However, there are a few powerful and interesting techniques stemming from combining polymorphism and templates, notably so-called type erasure.

sbi
+1 for mentioning type erasure. I was about to add a comment, then noticed you already mentioned it xD
Johannes Schaub - litb
+4  A: 

C++ doesn't allow virtual template member functions right now. The most likely reason is the complexity of implementing it. Rajendra gives good reason why it can't be done right now but it could be possible with reasonable changes of the standard. Especially working out how many instantiations of a templated function actually exist and building up the vtable seems difficult if you consider the place of the virtual function call. Standards people just have a lot of other things to do right now and C++1x is a lot of work for the compiler writers as well.

When would you need a templated member function? I once came across such a situation where I tried to refactor a hierarchy with a pure virtual base class. It was a poor style for implementing different strategies. I wanted to change the argument of one of the virtual functions to a numeric type and instead of overloading the member function and override every overload in all sub-classes I tried to use virtual template functions (and had to find out they don't exist.)

pmr
@pmr: A virtual function might be called from code that didn't even exist when the function was compiled. How would the compiler determine which instances of a (theoretical) virtual template member function to generate for code that doesn't even exist?
sbi
@sbi: Yes, separate compilation would be a huge problem. I'm no expert on C++ compilers at all so I cannot offer a solution. As with templated functions in general it should be instantiated again in every compilation unit, right? Wouldn't that solve the problem?
pmr
+1  A: 

The following code can be compiled and runs properly, using MinGW G++ 3.4.5 on Window 7:

#include <iostream>
#include <string>

using namespace std;

template <typename T>
class A{
public:
    virtual void func1(const T& p)
    {
        cout<<"A:"<<p<<endl;
    }
};

template <typename T>
class B
: public A<T>
{
public:
    virtual void func1(const T& p)
    {
        cout<<"A<--B:"<<p<<endl;
    }
};

int main(int argc, char** argv)
{
    A<string> a;
    B<int> b;
    B<string> c;

    A<string>* p = &a;
    p->func1("A<string> a");
    p = dynamic_cast<A<string>*>(&c);
    p->func1("B<string> c");
    B<int>* q = &b;
    q->func1(3);
}

and the output is:

A:A<string> a
A<--B:B<string> c
A<--B:3

And later I added a new class X:

class X
{
public:
    template <typename T>
    virtual void func2(const T& p)
    {
        cout<<"C:"<<p<<endl;
    }
};

When I tried to use class X in main() like this:

X x;
x.func2<string>("X x");

g++ report the following error:

vtempl.cpp:34: error: invalid use of `virtual' in template declaration of `virtu
al void X::func2(const T&)'

So it is obvious that:

  • virtual member function can be used in a class template. It is easy for compiler to construct vtable
  • It is impossible to define a class template member function as virtual, as you can see, it hard to determine function signature and allocate vtable entries.
Allopen
A class template may have virtual member functions. A member function may not be both a member function template and a virtual member function.
James McNellis