Назначение этого указателя для ссылки на ссылку на указатель
Должен ли следующий образец скомпилировать?
struct B;
struct A
{
A(B*&&){}
};
struct B : A
{
B() : A(this){}
};
int main(){}
На LWS с clang он компилируется, но с gcc я получаю:
нет известного преобразования для аргумента 1 из 'B * const' в 'B * &&'
и если я добавлю const
он скомпилируется.
Я хотел бы также указать, что MSVC тоже ошибается:
не может преобразовать параметр 2 из 'B * const' в 'B * &&'
поэтому похоже, что у нас есть ошибка в двух компиляторах.
ОШИБКИ
Ссылка на сообщение MSVC
Ссылка на ошибку GCC
Ответы
Ответ 1
Да, это должно скомпилировать.
Неправильно реализовать this
как cv T* const
(где cv - cv-квалификаторы для функции, если они есть, и T
- тип класса). this
не const
, а просто выражение prvalue встроенного типа (не изменяемое).
Многие люди думают, что, поскольку вы не можете изменить this
он должен быть const
, но, как уже однажды прокомментировал Йоханнес Шауб-либб, гораздо лучшее объяснение выглядит примерно так:
// by the compiler
#define this (__this + 0)
// where __this is the "real" value of this
Здесь ясно, что вы не можете изменить this
(скажем, this = nullptr
), но также ясно, что для такого объяснения не требуется const
. (И значение, которое у вас есть в вашем конструкторе, - это просто значение временного.)
Ответ 2
Я говорю, что clang прав - код должен компилироваться. По какой-то причине GCC считает, что this
указатель будет const
несмотря на следующее:
Тип this
в членной функции класса X
есть X*
. Если функция-член объявлена const
, тип этого - const X*
, если функция-член объявлена volatile
, тип этого является volatile X*
, и если функция-член объявлена const volatile
, тип этого const volatile X*
.
Таким образом, в этом случае this
должно быть prvalue B*
и идеально привязывается к B*&&
. Однако обратите внимание, что при привязке this
к ссылке rvalue значение this
будет скопировано во временный объект, и ссылка будет привязана к этому. Это гарантирует, что вы никогда не изменяете оригинал this
значения.
Ссылка на тип "cv1 T1
" инициализируется выражением типа "cv2 T2
" следующим образом: