Home > other >  class initalizer list using a templated constructor of baseclass
class initalizer list using a templated constructor of baseclass

Time:09-08

I like to create a registry of templated classes adressed through their polymorphic anonymous base-class. In order to construct these classes I need to store the type of the used template class in the base-class. I woulod like to make the design slim and pass the template class in the constructor of the baseclass through a custom templated constructor.

However my code fails, and i cannot figure out what the correct formulation would be. Any help appriciated:

#include <vector>
#include <string>
#include <typeinfo>
#include <memory>

class Store_Base {
    const std::string stored_type_name_;
 protected:   //ctor
    template<class  Tstored>
    Store_Base() : stored_type_name_(typeid(Tstored).name()) {};
 protected: // dtor
    virtual ~Store_Base() = default;
 public:
    std::string get_type_name() const {return stored_type_name_;}
};

template <class Tstored>
class Store : public Store_Base {
    const Tstored stored_;
 public:  //ctor
    Store(const Tstored stored)
            : Store_Base<Tstored>(), stored_(stored) {};  // !!! compile-error
 public:
    Tstored get_stored() const {return stored_;}
};


int main() {
    std::vector<std::unique_ptr<Store_Base>> my_vec;
    my_vec.emplace_back(std::make_unique< Store<int> >(42));

    my_vec.at(0)->get_type_name(); // >>> i
    ((Store<int>*)(my_vec.at(0).get()))->get_stored(); // >>> 42
    
    return 0;
}

CodePudding user response:

This

Store(const Tstored stored)
        : Store_Base<Tstored>()

is wrong, because it attempts to initialize the base class Store_Base<Tstored>, but Store_Base is not a template. The base class to be initialized is Store_Base not Store_Base<Tstored>.

The way to call a templated constructor is to have the template argument deduced. See here C template constructor.

You can use a tag to enable deduction:

#include <vector>
#include <string>
#include <typeinfo>
#include <memory>

template <typename T>
class Tag{};

class Store_Base {
    const std::string stored_type_name_;
 protected:   //ctor
    template<class  Tstored>
    Store_Base(Tag<Tstored>) : stored_type_name_(typeid(Tstored).name()) {};
 protected: // dtor
    virtual ~Store_Base() = default;
 public:
    std::string get_type_name() const {return stored_type_name_;}
};

template <class Tstored>
class Store : public Store_Base {
    const Tstored stored_;
 public:  //ctor
    Store(const Tstored stored)
            : Store_Base(Tag<Tstored>{}), stored_(stored) {};  // !!! compile-error
 public:
    Tstored get_stored() const {return stored_;}
};


int main() {
    std::vector<std::unique_ptr<Store_Base>> my_vec;
    my_vec.emplace_back(std::make_unique< Store<int> >(42));

    my_vec.at(0)->get_type_name(); // >>> i
    ((Store<int>*)(my_vec.at(0).get()))->get_stored(); // >>> 42
    
    return 0;
}

Note that I didn't change more than necessary and that this code still fails to compile due to the destructor of Store_Base being protected, ie std::unique_ptr cannot access it.

  • Related