如何不关心班级成员模板

时间:2015-11-13 13:19:52

标签: c++ templates c++11

我有两个班级:

template <class T1, class T2>
class foo{
    //something here
}

class bar{
    bar()=delete;
    bar(const foo& a): a(a){}
private:
    foo a;
}

此代码不起作用。

但是,我怎样才能实现这样的目标呢?

我知道我应该告诉使用的foo的类型是什么。但实际上,我不允许默认构造函数。所以,我不能在没有给出合适的bar的情况下制作foo的对象。为什么我必须告诉编译器那么T1T2是什么? / p>

3 个答案:

答案 0 :(得分:5)

您可以做的是将bar类编写为模板类。正如@nwp建议的那样,您可以将make_bar函数作为帮助,以避免在从bar创建foo时明确表达您的类型,如下所示:

template <class T1, class T2>
class foo {
    //something here
};

template<class T1, class T2>
class bar {
    public:
        bar()=delete;
        bar(const foo<T1,T2>& a): a(a){}
    private:
        foo<T1, T2> a;
};

template<class T1, class T2>
bar<T1, T2> make_bar(foo<T1,T2> const& f) {
    return bar<T1, T2>{f};
}

int main() {

    auto myFoo = foo<int, double>{};
    auto barintdouble = make_bar(myFoo);

}

答案 1 :(得分:3)

数据成员可以只有一种类型。 foo不是一种类型。它是一个模板。您不能将成员类型的扣除留给编译器。这在c ++中是不可能的。 †

您也不能将foo的引用传递给构造函数,因为foo不是类型。

你需要的是多态性。

DragonRock展示了如何使用模板实现静态多态:将bar定义为类模板。然后,您可以使用模板参数参数化成员的类型。您仍然需要明确指定模板参数,因此不会通过对构造函数的调用推断出它们。但是,您可以编写函数模板,该函数模板返回具有特定实例bar的类型的对象,模板参数取决于函数的模板参数。函数的模板参数可以从传递给它的参数中推导出来。

Walter演示了如何使用继承实现动态多态:将所有foo实例定义为具有公共基类。然后在bar中存储该基类类型的引用或指针。

为什么标准不允许从构造函数的调用中推断出数据成员的类型?您可能会问。好吧,我们假设你的例子是有效的c ++。现在考虑这段代码:

bar& b = get_me_a_bar();
auto f = b.foo;

f的类型是什么?在此代码中没有调用bar的构造函数,因此无法从中推断出它。然而,必须知道f的类型。当然,必须在get_me_a_bar或其他地方调用构造函数,但调用可能在另一个编译单元中。它将使O(n^2)编译速度变慢,其中n是编译单元的数量,以查找对构造函数的调用。如果调用构造函数的编译单元尚未编译,该怎么办?这种推论会产生对单位编译顺序的依赖。

TL; DR C ++是一种静态类型语言。在静态类型语言中,只要使用该变量,就必须在编译时知道变量的类型。成员变量的使用不一定与构造函数的使用一致。

答案 2 :(得分:1)

您的代码没有多大意义:您的数据成员bar::foo a表示的内容并不清楚。根据您真正想要实现的目标(您未能解释),这可能是特定类型foo<T1,T2>的对象,或者它可能是任何<的对象/ em> foo<T1,T2>类型。在前一种情况下,您还必须按照其他答案中的建议制作bar特定的,即类模板。

但是,如果任何foo<T1,T2>都没问题,那么你必须使用多态。

class base_foo {
  virtual void func() const = 0; // etc.
  virtual~base_foo() {}
};

template<typename T1, typename T2>
class foo : public base_foo
{
  void func() const override;
};

现在,您可以通过其基座foo<T1,T2>引用任何base_foo,但您无法在bar中轻松保存实际对象。最能反映初始代码的方法是在堆上存储真实的foo<T1,T2>,但通过指向base_foo的指针访问它。

class bar
{
  std::unique<base_foo> ptr;
public:
  template<typename T1,typename T2>
  bar(foo<T1,T2> const&obj)
  : ptr(new foo<T1,T2>(obj)) {}       // calls foo<T1,T2>::foo<T1,T2>(foo<T1,T2> const&)
};

在代码中制作原始对象的副本。