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.
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…
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With