Search code examples
c++templatesstatic-polymorphism

C++ static rather than dynamic polymorphism


I'm trying to build a generic algorithm. So far I have achieved this using class hierarchy and pointers, as in the example below:

struct Base{
    virtual double fn(double x){return 0;}
};

class Derived : public  Base{
    double A;
public:
    Derived(double a) : A(a) {}
    double fn(double x) { return A*x;}
};

//Some other implementations

class algo{
    double T;
    std::unique_ptr<Base> b_ptr;
public:
    algo(double t, std::unique_ptr<Base>& _ptr); //move constructor...
    //Some constructors
    double method(double x){ return T*b_ptr->fn(x);}

};

This set up is then implemented as follows:

int main(){
    std::unique_ptr<Derived> ptr(new Derived(5.4));
    algo(3.2,ptr);
    method(2.4);

    return 0;
}

This is a very simple example, of course, but it serves for my question. From what I understand, using derived classes in this way means that the method is chosen at run-time rather than at compile time. Since I do not need any dynamic behaviour from my algorithm - everything is determined at compile time - this is a needless loss of efficiency. Is there a way to do the above at compile time, i.e. static polymorphism?

From what I understand, it's only possible to get static polymorphism using templates. I haven't been able to find a implement templates with non-primitive types, however. As in the example above, I need derived classes with non-default constructors, which doesn't seem to be possible... Could anyone offer any solutions as to how this might be done?


Solution

  • Your Base class and Derived seem to represent a function only having a single member function, so we could most likely do away with the polymorphism completely and pass a function into algo:

    #include <iostream>
    #include <utility>
    
    template <class Function>
    class algo
    {
        double t;
        Function fn;
    
    public:
        algo(double t, const Function& fn)
            : t{t}, fn{fn}
        { }
        double method(double x){ return t * fn(x);}
    
    };
    
    template <class Function>
    algo<Function> make_algo(double t, Function&& fn)
    {
        return algo<Function>(t, std::forward<Function>(fn));
    }
    
    int main()
    {
        const double someValue = 123;
        const double anotherValue = 987;
    
        auto algo = make_algo(anotherValue, [someValue](double otherValue) {
            return someValue * otherValue;
        });
    
        std::cout << std::fixed << algo.method(321) << std::endl;
    }