Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Templated Virtual Function

Tags:

c++

Templated virtual member functions are not supported in C++ but I have a scenario where it would be ideal. Im wondering if someone has ideas for ways to accomplish this.

#include <iostream>


class Foo {
public:
    virtual void bar(int ){}
    // make a clone of my existing data, but with a different policy
    virtual Foo* cloneforDB() = 0;
};


struct DiskStorage {
    static void store(int x) { std::cout << "DiskStorage:" << x << "\n"; }
};

struct DBStorage {
    static void store(int x) { std::cout << "DBStorage:" << x << "\n"; }
};

template<typename Storage>
class FooImpl : public Foo {
public:
    FooImpl():m_value(0) {}
    template<typename DiffStorage>
    FooImpl(const FooImpl<DiffStorage>& copyfrom) {
        m_value = copyfrom.m_value;
    }
    virtual void bar(int x) {
        Storage::store(m_value);
        std::cout << "FooImpl::bar new value:" << x << "\n";
        m_value = x;
    }
    virtual Foo* cloneforDB() {
        FooImpl<DBStorage> * newfoo = new FooImpl<DBStorage>(*this);
        return newfoo;
    }
    int m_value;
};

int main()
{
    Foo* foo1 = new FooImpl<DiskStorage>();
    foo1->bar(5);
    Foo* foo2 = foo1->cloneforDB();
    foo2->bar(21);
}

Now if I want to clone the Foo implmemetation, but with a different Storagepolicy, I have to explicitly spell out each such implementation:

cloneforDB()
cloneforDisk()

A template parameter would have simplified that. Can anyone think of a cleaner way to do this? Please focus on the idea and not the example, since its obviously a contrived example.

like image 319
excalibur Avatar asked Dec 20 '12 15:12

excalibur


1 Answers

Usually if you want to use a virtual template method, it means that something is wrong in the design of your class hierarchy. The high level reason for that follows.

Template parameters must be known at compile-time, that's their semantics. They are used to guarantee soundness properties of your code.

Virtual functions are used for polymorphism, ie. dynamic dispatching at runtime.

So you cannot mix static properties with runtime dispatching, it does not make sense if you look at the big picture.

Here, the fact that you store something somewhere should not be part of the type of your method, since it's just a behavioral trait, it could change at runtime. So it's wrong to include that information in the type of the method.

That's why C++ does not allow that: you have to rely on polymorphism to achieve such a behavior.

One easy way to go would be to pass a pointer to a Storage object as an argument (a singleton if you just want one object for each class), and work with that pointer in the virtual function.

That way, your type signature does not depend on the specific behavior of your method. And you can change your storage (in this example) policy at runtime, which is really what you should ask for as a good practice.

Sometimes, behavior can be dictated by template parameters (Alexandrescu's policy template parameters for example), but it is at type-level, not method level.

like image 173
Qortex Avatar answered Oct 11 '22 17:10

Qortex