【问题标题】:How to pass instance of template to another instance of another template?如何将模板实例传递给另一个模板的另一个实例?
【发布时间】:2020-02-11 08:29:21
【问题描述】:

我有两个必须是模板的类模板 (C++)。我只是简化了他们的代码以显示问题的本质。如何将对象 (obj1) 从一个模板 (MyClass1) 传递到第二个模板 (MyClass2) 的另一个对象 (obj2)?我尝试通过模板参数和构造函数,但我仍然有编译错误。如何正确执行?重要的是,我不知道模板参数,因此解决方案是通用的,不适用于指定参数。对象应该通过指针或引用传递,我不需要它的副本。

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);
}

我不确定这是否与这个问题有关,但我正在使用标准设置在 Atmel Studio 7 中为 AVR 编写 C++ 代码。

【问题讨论】:

  • 您可以在MyClass2 中创建一个模板构造函数,它将接受MyClass1 类型的参数,并从中构造对象。
  • 如果您想将MyClass1 的实例保留为MyClass2成员,您可能会遇到麻烦,因为您使类型依赖于模板参数另一种类型。
  • 另外,浮点模板参数在 C++20 之前是非法的。这段代码真的可以用你的编译器编译吗?
  • 为什么所有这些模板参数?您的编译器将为您的类的每个不同实例化生成特定的类类型。通过查看您的代码,您似乎根本不需要模板,而是字段成员并将参数传递到构造函数参数中。
  • @Timo,你是对的。这个简化的代码无法编译。我只是想说明问题的本质。在实际代码中,没有整数,而是uint8_t端口定义等。@Fareanor,这也是为什么这是模板的原因。我在某些端口和引脚上有一个设备,在其他端口和引脚上有其他设备。这很好,两者都有不同的类型。另一个优点是它可以减少程序的重量。

标签: c++ templates avr atmega atmelstudio


【解决方案1】:

因为这个原因,您的代码不能用 C++11 编译:

非类型模板参数必须具有结构类型,即 以下类型之一(可选 cv 限定,限定符 被忽略):

  • 左值引用类型(对象或函数);
  • 整数类型;
  • 一个 指针类型(指向对象或函数);
  • 指向成员类型的指针(到 成员对象或成员函数);
  • 枚举类型;
  • std::nullptr_t; (C++11 起)
  • 浮点类型; (C++20 起)

关于你的核心问题,你可以这样做:

template<int m, int n, typename Obj1Type>
class MyClass2 {
    Obj1Type obj1_;

public:
    MyClass2() {
        // Do something
    }

    MyClass2(Obj1Type const& obj1) {
        obj1_ = obj1;
    }

    // ...
};

然后在 main:

int main() {
    MyClass1<4, 3> obj1;
    MyClass2<3, 2, MyClass1<4, 3>> obj2(obj1);

    obj1.foo(12);
    obj2.bar(1);
    obj2.zet(5);
}

看看live

更新

您也可以利用继承并为此创建一个简单的基类:

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;
    }

    // ...
};

然后在 main:

int main() {
    MyClass1<4, 3> obj1;
    MyClass2<3, 2> obj2(obj1);

    obj1.foo(12);
    obj2.bar(1);
    obj2.zet(5);
}

这使您无需在模板参数列表中声明模板。但是,这可能不是您的完美解决方案,因为它引入了对象切片。

看看live

【讨论】:

  • 酷!有用。真的很谢谢你。我也尝试过使用接口。 MyClass1 实现 MyClass1InterfaceMyClass2 接受此接口作为构造函数的参数。与您避免两次写入MyClass1&lt;4, 3&gt; 的解决方案相同。我知道我可以使用typedef。不幸的是,添加接口声明会使程序内存使用量增加 40 个字节,这与您的解决方案相比是很多的。
  • @catgiggle 第二个例子绝对不是你想要的。首先,它复制成员obj1_(您可能想要也可能不想要)。但更重要的是,这引入了对象切片,这是您几乎永远不会想要的。
  • @Timo ofc 这可能不是 OP 想要的。有很多需要改进的地方。我刚刚提到这是一种可能的选择
  • 是的!好多了。但是这个解决方案有一个问题。编译器抱怨说他不知道obj1.foo 里面的obj2.bar。在BaseMyClass1 中声明虚拟 foo (virtual int foo(int x) = 0;) 方法后,他抱怨说它是纯虚拟的。通过指针传递可以解决这个问题,但是会增加太多的内存使用。
  • @catgiggle 我想这是您在最初的问题中没有显示的内容?
【解决方案2】:

模板类接受另一个模板类作为模板参数。所以你可以为 Myclass2 传递类型名 T。 示例程序: 你可以试试这样的:

#include <iostream>
using namespace std;

template<typename T1>
class Myclass1
{
    public:
    Myclass1(T1 x):m1_x(x)
    {
        cout << "Myclass1 C'tor" << m1_x << endl;
    }
    T1 m1_x;

    T1 get_x()
    {
        return m1_x;
    }
};

template < typename T1 >
class Myclass2
{
    public:
    Myclass2(T1 x): m_x(x)
    {
        cout << "My class 2 C'tor with value"  << m_x.get_x() << endl;
    }

    public:
    T1 m_x;
};


int main()
{
    Myclass1 <int > obj1(5000);

    Myclass2< Myclass1 <int> > obj2 ( obj1 );
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-25
    • 2016-08-27
    相关资源
    最近更新 更多