简体   繁体   中英

C++ Polymorphic template class, instantiation of template type object

I have the following situation, where I want to instantiate an object of a template type.
I want the instantiation of the template type object to depend on the "instantiator" class.

template <class T>
class Base
{
public:
  Base(){}

  void do_something()
  {
    T obj = this->Test();
    // do something with object
  }

  virtual T Test()
  {
   return T(5);
  }
};


template <class T>
class Derived : public Base<T>
{
public:
  Derived() : Base<T>() {}
  virtual T Test()
  {
    return T(5, 6);
  }
};

class Test1
{
public:
  Test1(int x){}
};
class Test2 : public Test1
{
public:
  Test2(int x, int y) : Test1(x) {}
};

Later in my code I want to work with Base or Derived objects. They perform operations on a template type object ( obj ) in function do_something() . I want to let the instantiation of obj depend on the implementation of the Test() function. Base should only work with objects of type Test1 or derived classes of Test1 that have the same constructor. Derived should only work on objects that have the same constructor as Test2 .

Base<Test1>(); // works
Base<Test2>(); // doesn't work, but should not work by my design and throw a compile error
Derived<Test1>(); // same
Derived<Test2>();  // should work, but doesn't,
// since Base::Test() still exists, but cannot be compiled due to wrong constructor of T

Is there a way to implement the described behavior? Or is there a design change I can make?

You might change Base to be correct for any T :

template <class T>
class Base
{
public:
    Base(){}

    void do_something()
    {
        T obj = this->Test();
        // do something with object
    }

    virtual T Test()
    {
        if constexpr (std::is_constructible_v<T, int>) {
            return T(5);
        }
        throw std::runtime_error("should not be called");
    }
};

but

Base<Test2>(); would compile but throw at runtime.

Seems better to split and have two derived:

template <class T>
class Base
{
public:
    Base() = default;
    virtual ~Base() = default;

    void do_something()
    {
        T obj = this->Test();
        // do something with object
    }

    virtual T Test() = 0;
};

template <class T>
class Derived : public Base<T>
{
public:
  Derived() : Base<T>() {}
  T Test() override { return T(4); }
};

template <class T>
class Derived2 : public Base<T>
{
public:
  Derived() : Base<T>() {}
  T Test() override { return T(5, 6); }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM