Гарантированное завершение копирования и предварительное декларирование возвращаемого типа - PullRequest
5 голосов
/ 22 января 2020

Я хочу написать общий интерфейс с использованием 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 и гарантированным разрешением копирования, я ожидал, что компилятору больше не понадобится определение Объ при определении ф. Это возможно? Или обязательно #include obj.h в interface.h? Второй вариант раздражает, так как он значительно увеличивает время компиляции.

1 Ответ

3 голосов
/ 22 января 2020

Даже при «гарантированном разрешении копирования» (которое, к сожалению, немного ошибочно), стандарт C ++ требует [dcl.fct] / 11 , что возвращаемый тип функции

[…] не должно быть неполным (возможно, cv-квалифицированным) типом класса в контексте определения функции, если только функция не удалена.

Использование типа заполнителя для Тип возвращаемого значения в определении вашей функции (как было также предложено Максом Лангофом в комментариях) должен обойти проблему в этом случае:

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

рабочий пример здесь

Обратите внимание, что «гарантированное разрешение на копирование» на самом деле не является гарантией того, что копия будет удалена, так же как и изменение языка, означающее, что копия никогда не делается в первую очередь. Без наличия копии, исключать также нечего ...

Не делать копию означает, что компилятор должен создать объект непосредственно в месте назначения возвращаемого значения. И для этого требуется полный тип ...

...