我有一个c ++模板类,里面有一个嵌套类,类似于:
template<int d>
class Outer_t
{
public:
class Inner;
Inner i;
};
template<int d>
class Outer_t<d>::Inner
{
public:
float x;
};
int main ()
{
Outer_t<3> o_t; // 3 or any arbitrary int
o_t.i.x = 1.0;
return 0;
}
这个编译没有任何问题。但是,只要我声明一个类似的非模板类,就像这样:
class Outer_1
{
public:
class Inner;
Inner i;
};
class Outer_1::Inner
{
public:
float x;
};
int main ()
{
Outer_1 o1;
o1.i.x = 1.0;
return 0;
}
我开始收到以下错误(我使用的是gcc 4.6.3):&#34;错误:字段'i'的类型不完整&#34;。我知道我可以通过在外部类中定义内联类内联来解决这个问题:
class Outer_2
{
public:
class Inner {
public:
float x;
};
Inner i;
};
这将编译,但我想避免定义嵌套类内联。所以我有两个问题:模板与非模板嵌套类声明之间存在明显奇怪差异的原因是什么?是否有一种优雅的方式来声明和使用外部类中的nester类,同时避免将其定义为内联,与模板类的风格大致相同?在此先感谢您的帮助!
答案 0 :(得分:4)
编译器需要知道成员变量类型的大小才能进行对象布局。对于Outer_1
,因为Inner
只是一个前瞻性声明,我们不知道它的大小。因此编译错误。但是对于Outer_2
,定义是内联的,所以当我们到达Inner
类型的成员变量时,我们知道它的大小。
类模板在模板实例化发生之前无法定义。在您的示例中,隐式实例化发生在main
中。此时,Inner
的定义已完成,因此其大小已知。我们可以看到,在Inner
的定义之前使用显式实例化就是这种情况。
template<int d>
class Outer_t
{
public:
class Inner;
Inner i;
};
template class Outer_t<3>; // explicit instantation
template<int d>
class Outer_t<d>::Inner
{
public:
float x;
};
int main ()
{
Outer_t<3> o_t; // 3 or any arbitrary int
o_t.i.x = 1.0;
return 0;
}
Clang产生以下错误:
a.cc:7:11: error: implicit instantiation of undefined member 'Outer_t<3>::Inner'
Inner i;
^
a.cc:10:16: note: in instantiation of template class 'Outer_t<3>' requested here
template class Outer_t<3>;
^
a.cc:5:11: note: member is declared here
class Inner;
^
如果你想提取嵌套类的定义,我建议的解决方案是让它像Outer_t
一样进行模板化,但为方便起见提供别名。
template <typename Dummy = void>
class Outer_1_Impl {
public:
class Inner;
Inner i;
};
template <typename Dummy>
class Outer_1_Impl<Dummy>::Inner {
public:
float x;
};
using Outer_1 = Outer_1_Impl<>;
int main () {
Outer_1 o1;
o1.i.x = 1.0;
}
答案 1 :(得分:1)
在定义类时,对象中只能包含具有完整定义的非静态成员。在您的非模板示例中,Outer_1::Inner
显然不完整,因为它仅在目前为止声明。创建Inner
成员的唯一方法就是像Outer_2
一样定义它。
现在,为什么使用类模板时不会出现问题?答案是:当您在Outer_t
中实例化main()
时,实际上 可以访问Outer_t<T>::Inner
的完整定义! ...并且在使用某种类型Outer_t<T>
实例化T
之前,Outer_t
的定义并非真正需要。