Неполные типы в определениях функций-членов

[dcl.fct.def] p2 сообщает:

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

И [class.mem] p7 заявляет:

Класс считается полностью определенным типом объекта (или полным типом) при закрытии } спецификатора класса. Класс считается завершенным в контексте полного класса; в противном случае он считается неполным в пределах собственной спецификации члена класса.

Учитывая этот код:

struct S
{
  // S is incomplete
  S f() {  /* S is complete in a function body */ return S(); }
  // S is incomplete 
};
// S is complete

контекст полного класса, в частности, не включает в себя decl-specier-seq определения функции и не включает в себя декларатор функции, однако каждый компилятор говорит, что это нормально. Какая формулировка позволяет это, поскольку я не могу найти это?

Ответы

Ответ 1

Самый первый пункт по указанной ссылке:

Полный контекст класса - это

  • тело функции ([dcl.fct.def.general]),

Таким образом, в теле функции любого метода рассматривается контекст полного класса. Насколько я могу судить, "контекст определения функции" является синонимом тела функции, в отличие от контекста объявления функции, где тип возвращаемого значения не обязательно должен быть завершен.

Ответ 2

Я думаю, что компилятор сначала находит токены класса lex.phases 1.7 S (со всеми объявленными его членами) и функции-члена f (только с объявлением, которое включает тип возвращаемого значения). Затем они анализируются.

К тому времени, когда тело функции f анализируется, класс S сначала анализируется и считается завершенным, поскольку в нем определена функция-член (функция boby есть, она будет проанализирована позже).

Теперь S завершен, f может использовать return S().


Но это его другой случай:

struct S {
    decltype(S{}) f() { return S(); }
};

компилятор хочет найти тип S по decltype, чтобы расценивать токен (возвращаемый тип f), и терпит неудачу, потому что окончание класса }; еще не достигнуто.