C++ 函数返回T<;A>;不';在某些情况下不能编译
我不明白为什么C++ 函数返回T<;A>;不';在某些情况下不能编译,c++,templates,typedef,C++,Templates,Typedef,我不明白为什么func3()不能编译,而func2()和func4()可以编译 :错误:“B::my_t”的类型不完整 VS2008:错误C2079:“B::my_t”使用未定义的类“A” 模板 结构C{ T mt_T; }; 模板 结构B{ 类型定义C_类型; 我的,; }; 结构其他{}; 结构A{ B func2(); B::C_type func3();//错误:“B::my_t”的类型不完整 B::C_类型func4(); }; int main(){} 您可以将成员my\t存储
func3()
不能编译,而func2()
和func4()
可以编译
- :
错误:“B::my_t”的类型不完整
- VS2008:
错误C2079:“B::my_t”使用未定义的类“A”
模板
结构C{
T mt_T;
};
模板
结构B{
类型定义C_类型;
我的,;
};
结构其他{};
结构A{
B func2();
B::C_type func3();//错误:“B::my_t”的类型不完整
B::C_类型func4();
};
int main(){}
您可以将成员my\t
存储在模板结构B
中作为指针,并在结构B
中处理其构造、销毁和复制,如下所示:
template <typename T>
struct B
{
typedef C<T> C_type;
T* my_t;
};
模板
结构B
{
类型定义C_类型;
我的;
};
当您尝试获取B::C_type
时,必须实例化模板B
,但是您不能在不完整的类型上实例化模板,因为它包含一个成员对象T my\u T
,该对象不能是不完整的——编译器不知道您只想获取B
的成员typedef
在func2
中,您只使用B
作为返回类型,这是允许不完整的——我们不需要实例化B
来允许它作为返回类型。但是要访问成员(typedef),我们确实需要实例化B
。此外,func4
还可以,因为Other
是一个完整的类型
解决方案很简单,只需手动解析typedef,并将
func3
的返回类型转换为C
我认为相关段落来自第2章:
类被视为完全定义的对象类型(3.9)(或
类说明符的结尾}处的完整类型)。在
类成员规范,则该类在
函数体、默认参数、异常规范和
非静态数据成员的大括号或同等初始值设定项(包括
嵌套类中的此类内容)。否则将被视为不完整
在它自己的类成员规范中
B func2()//此处A不完整,但B未实例化
{
return B();//此处A已完成
}
B::C_type func3()//A不完整,需要为C_type实例化B
{
返回B::C_type();//好的,A已完成
}
这里有几个因素在起作用
A
不完整
首先,在所有函数声明中:
B<A> func2();
B<A>::C_type func3();
B<Other>::C_type func4();
B func2();
B::C_类型func3();
B::C_类型func4();
A
是不完整的类型:
[2003:9.2/2]:
类被视为完全定义的对象类型(3.9)(或
在类说明符的结束符}
处输入完整类型)。在
类成员规范,则该类在
函数体、默认参数和构造函数构造函数初始化器(包括嵌套类中的此类内容)否则将被视为
在其自身的类成员规范中不完整。
B
需要实例化
func2
和func4
正常
其次,函数返回类型可能不完整。这意味着func2
和func4
的返回类型与它们的方式一样好
[2003:8.3.5/6]:
[…]的参数类型或返回类型
函数定义不应是不完整的类类型(可能是
除非函数定义嵌套在
该类的成员规范(包括嵌套
类中定义的类)
func3
不正常
但是,在更复杂的func3
示例中,要使用类型B::C_type
,B
必须完整*
因此,它也必须被实例化:
[2003:14.7.1/1]:
除非类模板专门化
明确实例化(14.7.2)或明确专门化(14.7.3),
当
专门化是在需要
完全定义的对象类型或当类的完整性
类型影响程序的语义。[……]
但是,由于B
包含类型a
的成员,并且a
不是完整的类型,并且[8.3.5/6]
要求它是完整的类型,因此实例化无效,B
仍然不完整。。。而且这个计划的形式也不好
*我还没有找到支持这一点的引文,尽管这似乎很明显。这是一个循环引用: 为了让编译器理解结构
A
是什么,它必须能够理解B::C_type
(因为它包含返回此类型对象的成员)。因此,为了理解B::C_type
是什么,编译器必须理解B
是什么。但是为了理解B
是什么,编译器需要知道A
是什么
本质上,您给了编译器一个悖论:为了理解
a
是什么,您首先需要知道a
是什么。这是我编辑的。如果有人出于某种原因想找到旧标题,那么他们可以查看修订历史记录。@Dima:只有当周围的上下文是模板时,这才有效<代码>func3不是模板。问题是,但是函数签名。Terser testcase:函数调用在这里是不必要的复杂情况。typedef
的简单使用说明了问题:typedef B BA代码>正常,可用于不需要完整类型,但需要us的上下文中
B<A> func2() //A is incomplete here, but B<A> isn't instantiated
{
return B<A>(); //A is complete here
}
B<A>::C_type func3() //A is incomplete, B<A> needs to be instantiated for C_type
{
return B<A>::C_type(); //OK, A is complete
}
B<A> func2();
B<A>::C_type func3();
B<Other>::C_type func4();