templates may not be ‘virtual’

18,148

Solution 1

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&).

Solution 2

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

Solution 3

If you really need to make this method virtual, consider making CBar<> polymorphic and pass a base type in which isn't templated.

EDIT: something like this:

// non-templated base class
class BarBase
{
 // common methods go here..
};

template <typename BAR_TYPE>
class CBar : public BarBase
{
 // implement methods from BarBase ...
};

template < class FOO_TYPE>
class CFoo{
    public:
        ...
        // now we take the base type, and this method does not need to be a template
        virtual void doSomething( BarBase const* ptrBar );
        ...
        virtual ~CFoo();
    protected:
        MyClass < FOO_TYPE > * m_pClass;
};

template < class FOO_TYPE >
void CFoo<FOO_TYPE>::doSomething( BarBase const* ptrBar ){
..
}

Solution 4

Well, the error message is pretty clear. Member function templates can't be virtual. How to solve this depends on your problem, but the easiest thing to do would be to make the member functions non-virtual and reconsider your design.

Share:
18,148

Related videos on Youtube

Javier
Author by

Javier

Updated on May 20, 2022

Comments

  • Javier
    Javier almost 2 years

    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 ){
        ...
    }
    
    • Nim
      Nim over 13 years
      it's not a bug, it's a feature, you cannot declare a function template which is virtual. You need to explore another approach, and that depends on what you are trying to do...
  • Javier
    Javier over 13 years
    thanks. In my case, I need to have this "refBar" as parameter and it belongs to a templated class.
  • Bo Persson
    Bo Persson over 13 years
    Do you know how many different template parameters there will be? 3? 8? Can you overload the function for each of those? If you don't know, how will the compiler know how many virtual functions there are?
  • Javier
    Javier over 13 years
    @Bo: only 2 parameters: FOO_TYPE and BAR_TYPE
  • Javier
    Javier over 13 years
    thanks for the code illustration. I defined the doSomething method as template because of it's argument. There are only two template types, the one corresponding to CFoo and the other due to CBar. I think that by declaring CFoo<FOO_TYPE, BAR_TYPE> as a double template class should be OK. What do you think?
  • Viren
    Viren over 13 years
    yw. And yes, that should get rid of the error plus help you retain the dynamic-binding/virtualness for that function. If you want more details, look at this thread here (Rainbow is me :-) : groups.google.com/group/comp.lang.c++/browse_thread/thread/…
  • Bo Persson
    Bo Persson over 13 years
    I was rather thinking of the number of values possible for BAR_TYPE. If you know what they are, you can have that number of virtual functions, that are not templated.
  • v.oddou
    v.oddou over 10 years
    It could be known at link stage after all compilation units have been compiled. The standard is a little quick on discard here.
  • MSalters
    MSalters over 10 years
    @v.oddou: Not realistically. The linker would have to match all virtual calls to all possible base classes, and instantiate templates. Those instantiations then need to be compiled. Those new instantiations in turn may contain new virtual calls, so this process would have to be iterative.
  • MSalters
    MSalters over 6 years
    Formatted again, but that doesn't mean I like the answer. The "inline" comment suggest a lack of familiarity with C++. In-class definitions are inline by default. And you can't just put a template member definition in a .cpp file. That has to be visible at the point of instantiation.
  • Viren
    Viren about 6 years
    @MSalters the inline & virtual comment was made in 2011. I could not pull out a reference from c++ standards, but here is a quick link to that comment. Lack of knowing that is in fact lack of familiarity with the language. -> books.google.com/…