Search code examples
c++templatesoverridingstdvector

how to override base class with template child?


I have the following code.

#include <string>
#include <map>
#include <utility>
#include <vector>
#include <cmath>

class Configuration {
protected:
    static std::map<std::string, Configuration*> commands;
    static std::vector<Configuration*> commidx;

    const std::string name;
    const int index;
    int (*snippet)(float);

public:
    Configuration(std::string name, const int index, int (*snippet)(float))
            : name(std::move(name)), index(index), snippet(snippet) {}
    virtual ~Configuration() = default;
    virtual void set(float val) {}          //should we raise an error?
    virtual float get() { return NAN; }     //should we raise an error?
};

template<typename T>
class Config : public Configuration {
    const std::string type;
    const std::string def;
    T cur, min, max;

public:
    explicit Config(const char *name, int index, const char *_type, const char *def, int (*snippet)(float), T min , T max)
    : Configuration(name, index, snippet)
    , type(_type)
    , def(def)
    , min(min)
    , max(max)
    {
        if (type == "float") {
            cur = std::stof(def);
        } else if (type == "integer") {
            cur = std::stoi(def);
        } else if (type == "bool") {
            cur = std::stof(def) != 0;
        } else {
            SPDLOG_ERROR("unknownt type {}", type);
        }
    }

    void set(T val) override {
        if (val < min)   val = min;
        if (val > max)   val = max;
        if (val != cur) {
            val = cur;
            snippet(val);
        }
    }


    T get() override {
        return cur;
    }
};

std::vector<Configuration*> Configuration::commidx {
        new Config<float>("fff", 0, "float", "0.4", nullptr, 0, 1),
        new Config<bool>("bbb", 1, "bool", "0", nullptr, 0, 1),
        new Config<integer>("iii", 8, "int", "0", nullptr, 0, 3),
};

This bombs in compilation because set() and get() methods don't really override base class.

How can I achieve desired result: put in the same vector of pointers to slightly different template classes?


Solution

  • You can try something like following.

    #include <string>
    #include <map>
    #include <utility>
    #include <vector>
    #include <cmath>
    
    class Configuration
    {
    protected:
        static std::map<std::string, Configuration *> commands;
        static std::vector<Configuration *> commidx;
    
        const std::string name;
        const int index;
        int (*snippet)(float);
    
    public:
        Configuration(std::string name, const int index, int (*snippet)(float))
            : name(std::move(name)), index(index), snippet(snippet) {}
        virtual ~Configuration() = default;
    };
    
    template <typename T>
    class ConfigurationBase : public Configuration
    {
    
    public:
        ConfigurationBase(std::string name, const int index, int (*snippet)(float))
            : Configuration(name, index, snippet)
        {
        }
        //virtual void set(T val) {}
        //virtual T get() { return NAN; }
    
        virtual void set(T val) = 0;
        virtual T get() = 0;
    };
    
    template <typename T>
    class Config : public ConfigurationBase<T>
    {
        const std::string type;
        const std::string def;
        T cur, min, max;
    
    public:
        explicit Config(const char *name, int index, const char *_type, const char *def, int (*snippet)(float), T min, T max)
            : ConfigurationBase<T>(name, index, snippet), type(_type), def(def), min(min), max(max)
        {
            if (type == "float")
            {
                cur = std::stof(def);
            }
            else if (type == "integer")
            {
                cur = std::stoi(def);
            }
            else if (type == "bool")
            {
                cur = std::stof(def) != 0;
            }
            else
            {
                // SPDLOG_ERROR("unknownt type {}", type);
            }
        }
    
        void set(T val) override
        {
            if (val < min)
                val = min;
            if (val > max)
                val = max;
            if (val != cur)
            {
                val = cur;
                // snippet(val);
            }
        }
    
        T get() override
        {
            return cur;
        }
    };
    
    std::vector<Configuration *> Configuration::commidx{
        new Config<float>("fff", 0, "float", "0.4", nullptr, 0, 1),
        new Config<bool>("bbb", 1, "bool", "0", nullptr, 0, 1),
        new Config<int>("iii", 8, "int", "0", nullptr, 0, 3),
    };