正如answer所暗示的那样,我知道允许在函数声明中使用不完整类型作为返回值。所以我写了下面的代码:
Obj.h
class Obj {
int x;
};
f.h
class Obj;
Obj f();
f.cpp
#include "Obj.h"
Obj f() {
return Obj();
}
的main.cpp
#include "f.h"
int main() {
f();
return 0;
};
使用以下编译器编译此代码:
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
使用以下编译命令:
g++ *.cpp
给出以下错误:
main.cpp: In function 'int main()':
main.cpp:4:7: error: invalid use of incomplete type 'class Obj'
f();
^
f.h:1:7: error: forward declaration of 'class Obj'
class Obj;
^
因此编译器不允许在函数声明中使用不完整类型作为返回值。有什么解释?
答案 0 :(得分:8)
正如你自己所说的那样“允许在函数声明中使用不完整类型作为返回值”。这正是编译器允许你做的事情。您在非定义函数声明中成功使用了不完整的返回类型 - 您在f
中的f.h
声明编译没有任何问题。
但是你可以这么做。这绝不会改变以下事实:
在您的代码中,main()
内部尝试调用以不完整返回类型声明的函数。因此错误。
5.2.2函数调用[expr.call]
10 如果结果类型是左值,则函数调用是左值 引用类型或函数类型的右值引用,xvalue if 结果类型是对象类型的右值引用,和prvalue 否则。
11 如果函数调用是对象类型的prvalue:
- 如果 函数调用是 - decltype-specifier的操作数或 - 逗号运算符的右操作数,它是a的操作数 decltype-specifier,不引入临时对象 prvalue。 prvalue的类型可能不完整。 [...]
- 否则,prvalue的类型应为 完整。强>
换句话说,你被允许的是用不完整的返回类型引入你的函数的早期前向声明。但是当你到定义该函数或调用它时,你应该完成该返回类型。
答案 1 :(得分:2)
这里的问题是main.cpp
不知道Obj
是什么,所以当它编译main.cpp
时,由于返回类型,它无法调用f
不完整。您需要做的是将Obj
的定义引入main.cpp
。您可以使用#include "obj.h"
中的main.cpp
执行此操作。
答案 2 :(得分:1)
正如您所见,并非所有不完整的类型都被允许。实际上,规则是函数可以将指针或引用返回到不完整的类型。原因是在调用时,编译器必须能够生成代码来处理返回的对象。如果没有关于对象内容的信息,编译器就无法生成代码。例如,假设Obj
有一个非平凡的析构函数;如果编译器不知道,它就不能生成破坏对象的代码。当返回类型是指针或引用时,编译器具有所需的所有信息:指针和引用通常不依赖于目标对象的细节。