Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What should happen when the return value from a C++ function that returns a reference of an undefined object type is not assigned?

Tags:

c++

c++11

Consider the following code:

class Foo;

Foo& CreateFoo();


void Bar()
{
   CreateFoo();
}

In Visual Studio this will result in an error C2027 that Foo is an undefined type. In most other compilers it compiles fine. It is only an issue if the return value of CreateFoo is not assigned. If I change the line to:

Foo& foo = CreateFoo();

it compiles fine in Visual Studio. Also if Foo is defined rather than just forward-declared, then it will compile fine with no assignment.

Which should be the correct behavior? Is there anything in the C++ standard that addresses this, or is this something that is left to the implementation? I looked and didn't see anything that talks about this.

Update: A bug report has been filed.

like image 684
Gerald Avatar asked Aug 11 '12 01:08

Gerald


2 Answers

This looks like the relevant part of the Standard (section 5.2.2):

A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.

If a function call is a prvalue of object type:

  • if the function call is either

    • the operand of a decltype-specifier or

    • the right operand of a comma operator that is the operand of a decltype-specifier,

    a temporary object is not introduced for the prvalue. The type of the prvalue may be incomplete. [ Note: as a result, storage is not allocated for the prvalue and it is not destroyed; thus, a class type is not instantiated as a result of being the type of a function call in this context. This is true regardless of whether the expression uses function call notation or operator notation (13.3.1.2). — end note ] [ Note: unlike the rule for a decltype-specifier that considers whether an id-expression is parenthesized (7.1.6.2), parentheses have no special meaning in this context. — end note ]

  • otherwise, the type of the prvalue shall be complete.

Since this function result type is an lvalue reference type, the function call evaluates to an lvalue, and the completeness requirement does not apply.

The code is legal, at least in C++11, which no released version of Visual C++ implements fully.

like image 184
Ben Voigt Avatar answered Oct 13 '22 00:10

Ben Voigt


You can always use incomplete types in function declarations (since that only declares a signature of the function, not any real code), but not when you use it.

Calling CreateFoo(); is equals to (void) CreateFoo();, and my guess is that Visual Studio needs to inspect the code of Foo to do ANY conversion (I'm not sure if you can actually write a void conversion), because, for conversions you need a complete type.

As for Foo & foo = CreateFoo();, this does not do any conversions, so you can get away with having an incomplete type.

like image 42
Evan Dark Avatar answered Oct 12 '22 23:10

Evan Dark