Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

templates may not be ‘virtual’

Given the code below, the compiler is showing a message pointing that error: templates may not be ‘virtual’. Does anyone have a suggestion on how to solve the bug?

template < class FOO_TYPE>
class CFoo{
    public:
        ...
        template < class BAR_TYPE >
        virtual void doSomething( const CBar<BAR_TYPE> &); // here's the error
        ...
        virtual ~CFoo();
    protected:
        MyClass < FOO_TYPE > * m_pClass;
};

template < class FOO_TYPE >
template < class BAR_TYPE >
void CFoo<FOO_TYPE>::doSomething( const CBar<BAR_TYPE> & refBar ){
    ...
}
like image 874
Javier Avatar asked Feb 10 '11 19:02

Javier


2 Answers

The easiest reason to see why this is illegal is by considering the vtable. Sure, that's just one common implementation, and others are allowed. But all virtual functions in C++ are designed such that they can be implemented with a vtable.

Now, how many entries are there in the vtable of CFoo<int> ? Is there an entry for doSomething<float> ? And doSomething<float*>? And doSomething<float**> ? Templates such as these allow an infinite set of functions to be generated. Usually that's no problem, as you use only a finite subset, but for virtual functions this subset isn't known, and therefore the vtable would need to be infinite.

Now, it's possible that you really wanted only a single entry in the vtable. In that case, you'd write it as follows:

template < class FOO_TYPE, class BAR_TYPE>
class CFoo{
    public:
        ...
        virtual void doSomething( const CBar<BAR_TYPE> &); // now OK.
        ...
        virtual ~CFoo();
    protected:
        MyClass < FOO_TYPE > * m_pClass;
};

This means that the vtable for CFoo<int, float> will have one entry, for doSomething(float const&).

like image 98
MSalters Avatar answered Nov 03 '22 00:11

MSalters


You can use what we call in Symbian as "template design pattern". Here is sample code to give you an idea:

class Base {
public:
        virtual int DoSomething() = 0;
protected:
        Base();
};

class IntermediateBase : public Base {
protected:
        IntermediateBase(void* aSomeParam, void* aArg)
        : iSomeParam(aSomeParam)
        , iArgs(aArg) 
        {}

        virtual int DoSomething() = 0;
protected:
        void* iSomeParam;
        void* iArgs;
};

template <class TYPE, class INPUT>
class ConcreteClass : public IntermediateBase {
        typedef int (TYPE::*MemberFuncPtr)(const INPUT&);
public:
        ConcreteClass(TYPE& aCommandType, 
                      INPUT& aArgumentsToCommand,
                      MemberFuncPtr aMFP)
        : IntermediateBase(static_cast<TYPE*>(&aCommandType),
                           static_cast<INPUT*>(&aArgumentsToCommand) )
        , iMFP(aMFP)
        {}

        virtual int DoSomething()  // VIRTUAL AND INLINE Note - dont make it 
                                   // virtual and inline in production if 
                                   // possible to avoid out-of-line copy   
        {
            return static_cast<TYPE*>(iSomeParam)->*ConcreteClass::iMFP)
                           (*(static_cast<INPUT*>(iArgs));
        }
private:
        MemberFuncPtr iMFP;
}; 
like image 28
Viren Avatar answered Nov 03 '22 01:11

Viren