Search code examples
c++return-valuelanguage-lawyerreturn-typeforward-declaration

Does my Return Type Need to be Defined?


Forward declaration lets us postpone defining an actual type till the implementation file. This is allowed in the header for pointers or references to a forward declared type.

I have been told that:

Returning by value does not require the type definition. A forward declaration is sufficient

Can someone confirm or deny this with an actual quote from the standard? I was under the impression that this was not legal.


Solution

  • Returning by value does not require the type definition. A forward declaration is sufficient

    Declaring a function that returns by value does not require the type definition. A well-formed demo:

    struct S;
    S foo();
    struct S {};
    int main() {
        foo();
    }
    S foo() {
       return {};
    }
    

    Defining or calling a function that returns by value does require the type definition. Standard draft [basic.def.odr]:

    5 Exactly one definition of a class is required in a translation unit if the class is used in a way that requires the class type to be complete. [ Example: ... [snip] ... [ Note: The rules for declarations and expressions describe in which contexts complete class types are required. A class type T must be complete if:

    • [snip]
    • 5.9 a function with a return type or argument type of type T is defined ([basic.def]) or called ([expr.call]), or
    • [snip]

    The declaration of a function with incomplete return type is implicitly allowed by virtue of not being forbidden by any of the rules in the list.

    The rule is re-worded later in the standard, and it is relaxed by an exception [dcl.fct] (thanks to @cpplearner for pointing this rule out):

    11 Types shall not be defined in return or parameter types. The type of a parameter or the return type for a function definition shall not be an incomplete (possibly cv-qualified) class type in the context of the function definition unless the function is deleted ([dcl.fct.def.delete]).


    An ill-formed demo:

    struct S;
    S foo() {
        return {};
    } // oops
    struct S {};
    

    Another ill-formed demo:

    struct S;
    S foo();
    int main() {
        foo(); // oops
    }
    struct S {};
    S foo() {
        return {};
    }