Флейм
GameDev.ru / Флейм / Форум / When class becomes complete? [KRESTOPROBLEMY]

When class becomes complete? [KRESTOPROBLEMY]

Поделиться
Panzerschrek[CN]Участникwww11 окт. 201717:28#0
Суть такова:

Вроде как в крестах есть такая штука, что тела inline методов обрабатываются после обработки класса.

Пример:
https://ideone.com/q8VMlC

struct X{};

struct Y
{
  void Foo( X x ) // Here visible ::X
  {
    X new_x= x; // But here ::Y::X
  }
  
  struct X{};
};
И выдаёт он:
prog.cpp: In member function ‘void Y::Foo(X)’:
prog.cpp:7:12: error: conversion from ‘X’ to non-scalar type ‘Y::X’ requested
  X new_x= x; // But here ::Y::X


Как видно, из тела видно то, что объявляется позже, чем оно реально идёт.

Следуя этой логике, класс должен становится "complete" где-то после обработки компилятором определений его членов и перед построением кода inline-функций.

Но тогда вот такое:

struct F
{
  F Add( F a, F b )
  {
    return { a.f + b.f };
  }
  float f;
};

Не должно компилироваться, т. к. в сигнатуре функции используется класс "F" - который "incomplete".
Но оно компилируется: https://ideone.com/CrcKhR

WTF?


Вот кстати, ещё тема о похожих проблемах: http://www.gamedev.ru/flame/forum/?id=207787

Правка: 11 окт. 2017 18:29

Sbtrn. DevilПостоялецwww11 окт. 201717:39#1
Понять это невозможно! Нужно только запомнить! (c) анекдот
ZefickПостоялецwww11 окт. 201717:46#2
Panzerschrek[CN]
> Не должно компилироваться, т. к. в сигнатуре функции используется класс "F" - который "incomplete".
  В сигнатуре функции класс вообще и не должен быть complete, достаточно иметь его объявление. Ничего удивительного в том, что внутри класса его собственное объявление имеется в наличии, правда?
Panzerschrek[CN]Участникwww11 окт. 201717:52#3
Zefick
> В сигнатуре функции класс вообще и не должен быть complete

Хм, действительно, вот это:

struct X;

void Foo( X x );

int main(){}

компилируется: https://ideone.com/Cmp8VT


Хотя не понятно, почему должно. Для того, чтобы знать, как звать функцию, принимающую класс по значению, надо знать его содержание. В ABI различны способы вызова в зависимости от состава класса.

=A=L=X=Постоялецwww11 окт. 201717:55#4
Panzerschrek[CN]
> Для того, чтобы знать, как звать функцию, принимающую класс по значению, надо
> знать его содержание.

Для того чтобы знать как вызывать функцию - да. Но где ты тут увидел вызов функции то?

Panzerschrek[CN]Участникwww11 окт. 201717:59#5
=A=L=X=
> Для того чтобы знать как вызывать функцию - да. Но где ты тут увидел вызов
> функции то?
Таки да, логично.

Тогда вот ещё пример:

struct F
{
  void Foo( F f= F() );
  
  float f;
};

Параметр по умолчанию содержит вызов конструктора класса, который вроде как incomplete.
Но это компилируется: https://ideone.com/MhgkE6

return [](){};Участникwww11 окт. 201718:22#6
крестопроблемы уже не те
ZefickПостоялецwww11 окт. 201720:01#7
Panzerschrek[CN]
> Параметр по умолчанию содержит вызов конструктора класса, который вроде как incomplete.
  Опять таки с хрена ли этот же самый класс incomplete? Вот неработающий пример: https://ideone.com/KALp7Q
LУчастникwww11 окт. 201721:54#8
Zefick
Он как бы не совсем complete.
Вот так не получится:
class A {
public:
  static constexpr size_t Size = sizeof(A);
};


Именно потому что он incomplete в этом месте.

Panzerschrek[CN]Участникwww12 окт. 201715:56#9
L
> Он как бы не совсем complete.

Чертовщина какая-то. Типа, когда узнаём размер, то incomplete, а когда обрабатываем аргумены, то complete.

Или же аргументы по-умолчанию обрабатываются после тела класса?

Правка: 12 окт. 2017 15:56

PANDAПостоялецwww12 окт. 201716:31#10
Panzerschrek[CN]
> Хм, действительно, вот это:
>
> struct X;
>
> void Foo( X x );
>
> int main(){}
>
> компилируется
Ну ты тут только декларируешь функцию, ты ее внутренности определи (даже пустые) и не скомпилируется.

Жабистов не слушай, класс должен быть полностью определен, чтобы его можно было передавать по значению.

Правка: 12 окт. 2017 16:31

=A=L=X=Постоялецwww12 окт. 201716:32#11
Panzerschrek[CN]
> Или же аргументы по-умолчанию обрабатываются после тела класса?

Похоже на то, похоже что выражение в default value анализируется так же как и тело внедренной функции сразу после класса.
Если взять такой вот код с ошибкой из-за incomplete X: https://ideone.com/Qhwm0v
то его можно поправить либо переместив определение X выше F, либо убрав дефолтную инциализацию (и соответственно подставив X() в вызов метода в main).
То есть сама по себе декларация Foo не требует чтобы X был полностью описанным, но дефолтная инициализация судя по всему требует чтобы он был описан к концу описания класса F.

Правка: 12 окт. 2017 16:34

/ Форум / Флейм / Программирование

2001—2017 © GameDev.ru — Разработка игр