Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guaranteed copy elision and forward declaration of returned type

I want to write a common interface using CRTP, for all types that define some group of functions. The following code does not compile, because I call a function before the definition of its returned type:

// interface.h

struct Obj;

template <typename Derived>
struct Interface
{
    // error: return type 'struct Obj' is incomplete
    Obj f() const { return static_cast<const Derived&>(*this).f_impl(); }
};

// a.h

struct A : Interface<A>
{
    Obj f_impl();
};

// obj.h

struct Obj{};

// a.cpp

#include "a.h"
#include "obj.h"

Obj A::f_impl()
{
    return {};
}

With C++17 and guaranteed copy elision, I expected the compiler to no longer need the definition of Obj when defining f. Is this possible? Or is it mandatory to #include obj.h in interface.h? The second option is annoying since it considerably increases the compilation time.

like image 663
Thibaud Avatar asked Oct 15 '22 07:10

Thibaud


1 Answers

Even with "guaranteed copy elision" (which, unfortunately, is a bit of a misnomer), the C++ standard requires [dcl.fct]/11 that the return type of a function

[…] shall not be an incomplete (possibly cv-qualified) class type in the context of the function definition unless the function is deleted.

Using a placeholder type for the return type in your function definition (as was also suggested by Max Langhof in the comments) should work around the problem in this case:

template <typename Derived>
struct Interface
{
    auto f() const { return static_cast<const Derived&>(*this).f_impl(); }
};

working example here

Note that "guaranteed copy elision" really is not a guarantee that a copy will be elided as much as it is a change to the language that means that a copy is never made in the first place. Without there being a copy, there is also nothing to elide…

Not making a copy means the compiler has to construct an object directly in the destination of the return value instead. And doing so requires a complete type…

like image 102
Michael Kenzel Avatar answered Oct 31 '22 14:10

Michael Kenzel