Hanna Khalil
Hanna Khalil

Reputation: 1055

Forward declaration of returned type of function

As this answer suggests, I know that it's allowed to use incomplete types as a return value in function's declaration. So I wrote the following code:

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;
};

Compiling this code with the following compiler:

g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)

using the following compilation command:

g++ *.cpp

gives the following error:

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;
       ^

So the compiler is not allowing using incomplete type as a return value in a function's declaration. What's the explanation?

Upvotes: 15

Views: 8162

Answers (3)

AnT stands with Russia
AnT stands with Russia

Reputation: 320631

As you stated it yourself "it's allowed to use incomplete types as a return value in function's declaration". That's exactly what the compiler allowed you to do. You successfully used an incomplete return type in non-defining function declaration - your declaration of f in f.h compiles without any problems.

But that's all you are allowed to do. And this does not in any way change the fact that:

  1. At the point of function definition the return type shall be complete
  2. At the point of function call the return type shall be complete.

In your code, inside main() you attempt to call a function declared with incomplete return type. Hence the error.

5.2.2 Function call [expr.call]

10 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.

11 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. [...]

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

In other words, what you are allowed is to introduce an early forward declaration of your function with incomplete return type. But by the time you get to defining that function or calling it, you should have that return type completed.

Upvotes: 19

NathanOliver
NathanOliver

Reputation: 180945

The issue here is that main.cpp has no idea what Obj is so when it goes to compile main.cpp it can't call f since the return type is incomplete. What you need to do is introduce the definition of Obj to main.cpp. You can do this with a #include "obj.h" in main.cpp.

Live example

Upvotes: 4

Pete Becker
Pete Becker

Reputation: 76438

As you've seen, not all incomplete types are allowed. In fact, the rule is that a function can return a pointer or reference to an incomplete type. And the reason for that is that at the point of the call, the compiler has to be able to generate code to deal with the returned object. When there's no information about the content of the object, the compiler can't generate code. For example, suppose Obj has a non-trivial destructor; if the compiler doesn't know that, it can't generate code to destroy the object. When the return type is a pointer or a reference, the compiler has all the information it needs: pointers and references don't, in general, depend on the details of the target object.

Upvotes: 1

Related Questions