Template class inheritance

27,000
CDerived<int> di(dd1); // <- The problem is here

This invokes the first constructor of CDerived, and so T2 is inferred as CDerived<double> which is the type of dd1. Then, dd1 becomes x in the constructor; x which is CDerived<double>, gets passed to the base class constructor which accepts int (which is the value of the type argument T to CDerived class template). Hence the error, as CDerived<double> cannot be converted into int. Note that T of CBase is int.

See it as:

CDerived<int> di(dd1); // <- The problem is here
          ^       ^
          |       |
          |       this helps compiler to deduce T2 as double
          |
          this is T of the CDerived as well as of CBase

If you want to make your code work, then do this:

  1. First derive publicly instead of privately.
  2. Add another constructor taking CDerived<T2> as parameter.

So you need to so this:

template<class T> class CDerived : public CBase<T>  //derived publicly
{
    public:
        template <class T2> CDerived(const T2 &x) : CBase<T>(x) {;}

        //add this constructor
        template <class T2> CDerived(const CDerived<T2> &x) : CBase<T>(x.var()) {;}

        template <class T2> CDerived (const CBase<T2> &x) : CBase<T>(x) {;}
        ~CDerived() {;}
};

It should work now : online demo

Share:
27,000
Vincent
Author by

Vincent

Researcher, astrophysicist, computer scientist, programming language expert, software architect and C++ standardization committee member. LinkedIn: https://www.linkedin.com/in/vincent-reverdy

Updated on July 09, 2022

Comments

  • Vincent
    Vincent almost 2 years

    I have a problem with the following piece of code (it is a very simplified example that reproduce the error in my program) :

    #include <iostream>
    
    using namespace std;
    
    template<class T> class CBase
    {
        public:
            template <class T2> CBase(const T2 &x) : _var(x) {;}
            template <class T2> CBase (const CBase<T2> &x) {_var = x.var();}
            ~CBase() {;}
            T var() const {return _var;}
        protected:
            T _var;
    };
    
    template<class T> class CDerived : public CBase<T>
    {
        public:
            template <class T2> CDerived(const T2 &x) : CBase<T>(x) {;}
            template <class T2> CDerived (const CBase<T2> &x) : CBase<T>(x) {;}
            ~CDerived() {;}
    };
    
    int main()
    {
        CBase<double> bd(3);
        CBase<int> bi(bd); // <- No problem
        CDerived<double> dd1(3);
        CDerived<double> dd2(dd1);
        CDerived<int> di(dd1); // <- The problem is here
        return 0;
    }
    

    And the error is the following :

    error: cannot convert 'const CDerived<double>' to 'int' in initialization
    

    How to solve that ? (with a preference for modifications in the base class and not in the derived class, and if possible no use of virtuality)

    Thank you very much

    EDIT : If I replace the concerned line with : CDerived<int> di(CBase<int>(CBase<double>(dd1))); it works but it is not very practical...

    EDIT : Seems to be solved by that :

    template <class T2> CDerived(const CDerived<T2> &x) : CBase<T>(static_cast<const CBase<T2>&>(x)) {;}