我有两个班级:
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
的对象。为什么我必须告诉编译器那么T1
和T2
是什么? / p>
答案 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&)
};
在代码中制作原始对象的副本。