1

I would like to be able to provide to the base class MCFormater a formatting method that would work for different types (uint32, uint8...)

class MCFormater {
    public:
    MCFormater() {}
    virtual ~MCFormater() {}
    virtual mcc_t Gen();
protected:
    template<typename K>                          //here is the problem
    virtual void Format(K& a, const K& b) = 0; 
    //...
    uint32_t a;
    uint8_t b;
    void Foo();
};

void MCFormater::Foo() {
   Format<uint32_t>(a, 3);     //I want to be able to call for Format
   Format<uint8_t>(b, 3);      //with uint32_t, and uint8_t, and more 
}


class GFormater : public MCFormater {
    GFormater() {}
    template<typename K>
    virtual void Format(K& a, const K& b) {
        a = b;
    }
};

class EFormater : public MCFormater {
    EFormater() {} 
    template<typename K>
    virtual void Format(K& a, const K& b) {
        a |= b;
    }
};

but I get the error: templates may not be 'virtual'. what is the right way to do it? (is there one?)

Todder
  • 85
  • 1
  • 6

1 Answers1

3

Modify...

class MCFormater {
    public:
    MCFormater() {}
    virtual ~MCFormater() {}
    virtual mcc_t Gen();
protected:
    template<typename K>                          //here is the problem
    virtual void Format(K& a, const K& b) = 0; 
    //...
    uint32_t a;
    uint8_t b;
    void Foo();
};

void MCFormater::Foo() {
   Format<uint32_t>(a, 3);
   Format<uint8_t>(b, 3);
}


class GFormater : public MCFormater {
    GFormater() {}
    template<typename K>
    virtual void Format(K& a, const K& b) {
        a = b;
    }
};

class EFormater : public MCFormater {
    EFormater(FTEKeeps* keeps) : MCFormater(keeps) {} 
    template<typename K>
    virtual void Format(K& a, const K& b) {
        a |= b;
    }
};

To...

#include<iostream>

using namespace std;

template<typename K>
class MCFormater {
public:
    MCFormater() {}
    virtual ~MCFormater() {}
    virtual mcc_t Gen();
protected:  
    virtual void Format(K& a, const K& b) = 0;
    //...
    uint32_t a;
    uint8_t b;
    void Foo();
};

template<typename K>
void MCFormater<K>::Foo() {
    Format<uint32_t>(a, 3);
    Format<uint8_t>(b, 3);
}

template<typename K>
class GFormater : public MCFormater<K> {
    GFormater() {}  
    virtual void Format(K& a, const K& b) {
        a = b;
    }
};

template<typename K>
class EFormater : public MCFormater<K> {
    EFormater(FTEKeeps* keeps) : MCFormater<K>(keeps) {}    
    virtual void Format(K& a, const K& b) {
        a |= b;
    }
};

Explanation: Member function templates cannot be virtual. If this was allowed then the linker would have to add a new entry to the virtual table every time the Format function was called with a different type. Dynamic linking would be unacceptably complicated.

David G
  • 94,763
  • 41
  • 167
  • 253
dspfnder
  • 1,135
  • 1
  • 8
  • 13
  • I cant force the type K from outside the base class, as K differs inside the base class – Todder Jan 18 '15 at 12:32
  • "Member functions cannot be virtual" , **template** belongs at the beginning of that sentence. And it is worth noting that template class members *can* be virtual, but not template member *functions* (which your code shows, but doesn't mention in the explanation). – WhozCraig Jan 18 '15 at 12:32
  • @Todder then you have a design problem. You cannot have a virtual template member function. If you have to, provide overloads or a non-member template function that accepts your object as one of its parameters. – WhozCraig Jan 18 '15 at 12:34
  • 1
    Can't you explain what change you made? Mentally diffing this wall of code is not easy. – Lightness Races in Orbit Jan 18 '15 at 15:45
  • 1
    I didn't think that the differences between the Before and After versions of the code were difficult to see. It the person who asked the question would like me to explain them further, I would be happy to. – dspfnder Jan 18 '15 at 22:11