Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
270 views
in Technique[技术] by (71.8m points)

c++ - How to design around the limitation that templated member functions can't be virtual

I'm running into a design issue where (in C++) I'd like a templated member function (of a non-template class) to be virtual and am wondering if there is a good, elegant way around the issue.

The scenario goes, I have machines that process generic items. I use an abstract base class for machines with a virtual process(Item) function so that each machine can define their own unique processing method. The problem is that the items are also "generic" in that they expose certain interfaces for how they can be processed. For reasons (mainly for performance...no vtable overhead), I'd like to use compile-time polymorphism for these items. So that now each machine would have an interface like:

class Machine
{ public:
    template <typename T>
    virtual void process(T& item) = 0; 
};

However this is impossible in C++ as templated member functions cannot be virtual. certainly I can make the machine class templated on the Item type T but this adds more headaches for me in the larger design scheme and really no other part of the Machine class depends on Item...it's only an argument to the process() function.

Is there a better way around this or any suggestions for how to provide this kind of generic family of machines that process a family of generic items (where the items use compile-time polymorphism). Am I off the deep end in terms of my design.

Appreciate any suggestions

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Typically, double dispatch is used.

class Machine;
class Item {
public:
    virtual void bounce(Machine& mach);
};
class Machine {
public:
    template<typename T> void process(T& t);
    virtual void process(Item& i) {
        return i.bounce(*this);
    }
};
template<typename T> class CRTPItem {
public:
    virtual void bounce(Machine& mach) {
        return mach.process(*(T*)this);
    }
};
class ConcreteItem : public CRTPItem<ConcreteItem> {
public:
    // blah blah
};

In this case, you don't need virtual overhead for the whole ConcreteItem interface, and they don't need anything in common, just that one bounce function which is built for you automatically by inheriting from CRTPItem. This is only two vtable calls as opposed to the one you had originally, as opposed to needing a vtable call for all of Item's functions, and the interface can still retain all strong-typing that it would have if you could create virtual templates.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...