5

考虑以下代码:

class Foo;

Foo& CreateFoo();


void Bar()
{
   CreateFoo();
}

在 Visual Studio 中,这将导致错误 C2027 表明 Foo 是未定义的类型。在大多数其他编译器中,它编译得很好。如果未分配 CreateFoo 的返回值,这只是一个问题。如果我将行更改为:

Foo& foo = CreateFoo();

它在 Visual Studio 中编译得很好。此外,如果 Foo 被定义而不仅仅是前向声明,那么它会在没有赋值的情况下编译得很好。

哪个应该是正确的行为?C++ 标准中是否有任何东西可以解决这个问题,或者这是留给实现的东西?我看了看,没有看到任何关于这个的东西。

更新: 已提交错误报告。

4

2 回答 2

6

这看起来像标准的相关部分(第 5.2.2 节):

如果结果类型是左值引用类型或对函数类型的右值引用,则函数调用是左值,如果结果类型是对对象类型的右值引用,则为 xvalue,否则为纯右值。

如果函数调用是对象类型的纯右值:

  • 如果函数调用是

    • decltype 说明符的操作数或

    • 逗号运算符的右操作数,它是decltype-specifier的操作数,

    没有为纯右值引入临时对象。prvalue 的类型可能不完整。[注意:因此,prvalue没有分配存储,也没有被销毁;因此,在此上下文中,由于是函数调用的类型,因此不会实例化类类型。无论表达式使用函数调用表示法还是运算符表示法 (13.3.1.2),这都是正确的。— end note ] [ 注意:与 decltype-specifier 的规则不同,它考虑 id-expression 是否带括号(7.1.6.2),括号在此上下文中没有特殊含义。——尾注]

  • 否则,prvalue的类型应该是完整的。

由于此函数结果类型是左值引用类型,因此函数调用的计算结果为左值,不适用完整性要求。

该代码是合法的,至少在 C++11 中是合法的,没有任何已发布的 Visual C++ 版本完全实现了该代码。

于 2012-08-11T01:23:46.667 回答
1

您始终可以在函数声明中使用不完整类型(因为它仅声明函数的签名,而不是任何实际代码),但在使用时则不行。

调用CreateFoo();等于(void) CreateFoo();,我的猜测是 Visual Studio 需要检查 Foo 的代码来进行任何转换(我不确定您是否真的可以编写 void 转换),因为对于转换,您需要一个完整的类型。

至于Foo & foo = CreateFoo();,这不会进行任何转换,因此您可以避免使用不完整的类型。

于 2012-08-11T01:44:50.337 回答