Search code examples
c++templatesavratmegaatmelstudio

How to pass instance of template to another instance of another template?


I have two class templates that must be templates (C++). I just simplified their code to show the essence of the problem. How to pass an object (obj1) from one template (MyClass1) to another object (obj2) from second template (MyClass2)? I tried through the template parameter and the constructor, but I still have compilation errors. How to do it correctly? What is important, I don't know template parameters, therefore solution has be universal, not for specified parameters. Object should be passed by pointer or reference, I don't need its copy.

template<int a, int b>
class MyClass1 {
  public:
    MyClass1() {
        // Do something...
    }

    int foo(int x) {
        return a * x + b;
    }
};
template<double m, double n>
class MyClass2 {
  public:
    MyClass2() {
        // Do something
    }

    double bar(int x) {
        // Do something with x using object of MyClass1 and then with m...
    }

    double zet(int x) {
        // Do something with x using object of MyClass1 and then with n...
    }
};
int main() {
    MyClass1<4, 3> obj1;
    MyClass2<3.14, 2.56> obj2; // <-- How to pass obj1 here???
    // Maybe that way?: MyClass2<3.14, 2.56, obj1> obj2;
    // Or that way?: MyClass2<3.14, 2.56> obj2(obj1);

    obj1.foo(12);
    obj2.bar(1.234);
    obj2.zet(5.678);
}

I'm not sure if this is relevant to this problem, but I'm writing C++ code for AVR in Atmel Studio 7 with standard settings.


Solution

  • Your code does not compile with C++11 because of this:

    A non-type template parameter must have a structural type, which is one of the following types (optionally cv-qualified, the qualifiers are ignored):

    • lvalue reference type (to object or to function);
    • an integral type;
    • a pointer type (to object or to function);
    • a pointer to member type (to member object or to member function);
    • an enumeration type;
    • std::nullptr_t; (since C++11)
    • a floating-point type; (since C++20)

    Regarding your core problem, you can do the something like this:

    template<int m, int n, typename Obj1Type>
    class MyClass2 {
        Obj1Type obj1_;
    
    public:
        MyClass2() {
            // Do something
        }
    
        MyClass2(Obj1Type const& obj1) {
            obj1_ = obj1;
        }
    
        // ...
    };
    

    And then in main:

    int main() {
        MyClass1<4, 3> obj1;
        MyClass2<3, 2, MyClass1<4, 3>> obj2(obj1);
    
        obj1.foo(12);
        obj2.bar(1);
        obj2.zet(5);
    }
    

    Check it out live

    UPDATE

    You could also make use of inheritance and create a simple base class for this purpose:

    class BaseMyClass1 {};
    
    template<int a, int b>
    class MyClass1 : public BaseMyClass1 {
        // ...
    };
    
    template<int m, int n>
    class MyClass2 {
        BaseMyClass1 obj1_;
    
    public:
        MyClass2() {
            // Do something
        }
    
        template <typename Obj1Type>
        MyClass2(Obj1Type const& obj1) {
            obj1_ = obj1;
        }
    
        // ...
    };
    

    And then in main:

    int main() {
        MyClass1<4, 3> obj1;
        MyClass2<3, 2> obj2(obj1);
    
        obj1.foo(12);
        obj2.bar(1);
        obj2.zet(5);
    }
    

    This saves you declaring a template in template parameter list. However, this might not be the perfect solution for you because it introduces object slicing.

    Check it out live