How to simulate virtuality for a method template

I have a class hierarchy where I want to introduce a method template that will behave as if it were virtual. For example, a simple hierarchy:

class A { virtual ~A() {} template<typename T> void method(T &t) {} }; class B : public A { template<typename T> void method(T &t) {} }; 

Then I create object B:

 A *a = new B(); 

I know that I can get the type stored in a on typeid(a) . How can I name the correct B::method dynamically when I know the type? Perhaps I could have this state:

 if(typeid(*a)==typeid(B)) static_cast<B*>(a)->method(params); 

But I would like to avoid such conditions. I was thinking of creating std::map with typeid as the key, but what would I put as the value?

+4
source share
5 answers

You can use the "Curiously Recurring Template Pattern" http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

Using this template, the base class accepts the type of the derived class as the template parameter, which means that the base class can refer to the derived type to call functions in the derived class. This is a kind of compilation of the implementation time of virtual functions, with the added benefit of having to call a virtual function.

 template<typename DERIVED_TYPE> class A { public: virtual ~A() {} template<typename T> void method(T &t) { static_cast<DERIVED_TYPE &>(*this).methodImpl<T>(t); } }; class B : public A<B> { friend class A<B>; public: virtual ~B() {} private: template<typename T> void methodImpl(T &t) {} }; 

Then it can be used as ...

 int one = 1; A<B> *a = new B(); a->method(one); 
+6
source

Is there any general code that you could extract and make virtual?

 class A { virtual ~A() {} template<typename T> void method(T &t) { ... DoSomeWork(); ... } virtual void DoSomeWork() {} }; class B : public A { virtual void DoSomeWork() {} }; 
+2
source

As you know, you cannot have templates for virtual functions, since all virtual functions are part of the class type and must be known in advance. This excludes any simple “arbitrary redefinition”.

If this is an option, you can make part of the class template parameter:

 template <typename T> class A { protected: virtual void method(T &); }; template <typename T> class B : public A<T> { virtual void method(T &); // overrides }; 

A more attractive approach might use some dispatcher object:

 struct BaseDispatcher { virtual ~BaseDispatcher() { } template <typename T> void call(T & t) { dynamic_cast<void*>(this)->method(t); } }; struct ConcreteDispatcher : BaseDispatcher { template <typename T> void method(T &); }; class A { public: explicit A(BaseDispatcher * p = 0) : p_disp(p == 0 ? new BaseDispatcher : p) { } virtual ~A() { delete p_disp; }; private: BaseDispatcher * p_disp; template <typename T> void method(T & t) { p_disp->call(t); } }; class B : public A { public: B() : A(new ConcreteDispatcher) { } // ... }; 
+1
source

<sub> Unfortunately,. Originally answered on the wrong question - ok, on another question

After some thought, I understood this as a classic multi-method requirement, that is, a method that dispatches more than one parameter based on the runtime type. Ordinary virtual functions are compared by single dispatch (and they are sent only by the type this ).

Refer to the following:

  • Andrei Alexandrescu wrote (seed bits for C ++?) About the implementation of multi-methods using generics in "Modern C ++ Design"
    • Chapter 11: "Multimethods" - it implements the basic multi-methods, making them logarithmic (using ordered lists), and then all the way to multidimensional time constant methods. Powerful enough material!
  • A code article that seems to have this implementation:
    • do not use drop types of any type (dynamic, static, reinterpret, const or C-style)
    • do not use RTTI;
    • lack of preprocessor;
    • strong type security;
    • separate compilation;
    • constant runtime of the multimethod;
    • no dynamic memory allocation (via new or malloc) during a call using several methods;
    • lack of using non-standard libraries;
    • only standard C ++ functions are used.
  • C ++ Open Method Compiler , Peter Pirkelbauer, Yuri Solodky and Bjarn Straustrup
  • Loki library has MultipleDispatcher
  • Wikipedia has a pretty nice simple post with examples in Multiple Dispatch in C ++.

Here is a simple approach from the wikipedia article for reference (a less simple approach scales to more derived types):

<sub>

 // Example using run time type comparison via dynamic_cast struct Thing { virtual void collideWith(Thing& other) = 0; } struct Asteroid : Thing { void collideWith(Thing& other) { // dynamic_cast to a pointer type returns NULL if the cast fails // (dynamic_cast to a reference type would throw an exception on failure) if (Asteroid* asteroid = dynamic_cast<Asteroid*>(&other)) { // handle Asteroid-Asteroid collision } else if (Spaceship* spaceship = dynamic_cast<Spaceship*>(&other)) { // handle Asteroid-Spaceship collision } else { // default collision handling here } } } struct Spaceship : Thing { void collideWith(Thing& other) { if (Asteroid* asteroid = dynamic_cast<Asteroid*>(&other)) { // handle Spaceship-Asteroid collision } else if (Spaceship* spaceship = dynamic_cast<Spaceship*>(&other)) { // handle Spaceship-Spaceship collision } else { // default collision handling here } } } 

sub>

0
source

All Articles