保证复制省略和返回类型的前向声明

Guaranteed copy elision and forward declaration of returned type

我想使用 CRTP 为定义了一组函数的所有类型编写一个通用接口。 以下代码无法编译,因为我在定义其返回类型之前调用了一个函数:

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

使用 C++17 和保证复制省略,我希望编译器在定义 f 时不再需要 Obj 的定义。这可能吗?还是必须在 interface.h 中#include obj.h?第二个选项很烦人,因为它大大增加了编译时间。

即使使用 "guaranteed copy elision"(不幸的是,这有点用词不当),C++ 标准要求 [dcl.fct]/11 函数的 return 类型

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

在函数定义中为 return 类型使用占位符类型(正如 Max Langhof 在评论中所建议的那样)应该可以解决这种情况下的问题:

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

工作示例here

请注意,"guaranteed copy elision" 确实不能保证副本会被删除,因为它是对语言的更改,这意味着从一开始就不会制作副本。没有副本,也没有什么可以省略的……

不进行复制意味着编译器必须直接在 return 值的目标中构造一个对象。这样做需要一个完整的类型…