GCC не может перехватить указатель this на шаблонный тип с помощью init-capture
Шаблонный класс может захватывать свой собственныйthis
указатель в лямбде:
template <typename T>
class Foo {
public:
void foo(void) {}
auto getCallableFoo(void) {
return [this]() { this->foo(); };
}
};
Это и все остальноеFoo
примеры можно протестировать с помощью следующего кода:
int main()
{
Foo<int> f;
auto callable = f.getCallableFoo();
callable();
}
Однако, если вместо этого используется init-capture, это больше не работает с GCC:
auto getCallableFoo(void) {
return [ptr = this]() { ptr->foo(); };
}
Сообщение об ошибке (из GCC 5.1):
error: ‘Foo<T>::getCallableFoo()::<lambda()>::__ptr’ has incomplete type
Clang 3.7, кажется, компилирует и запускает этот код без ошибок. (Я на самом деле использую версию, скомпилированную из исходного кода до 3.7, но я не ожидаю, что с тех пор она сломалась.)
Инициализация захвата должна вести себя как назначениеauto
, но следующий код работает без ошибок в GCC:
// New method in Foo:
auto getPtr(void) {
return this;
}
// Usage:
auto ptr = f.getPtr();
ptr->foo();
Так почему же неptr
значение, способное захватитьthis
в GCC? Это ошибка?
Еще одно соображение заключается в том, чтосогласно CppReference, this
рассматривается как отдельныйсинтаксический регистр из любого другого типа списка захвата. Так что это может быть одним намеком на то, почему GCC относится к этим случаям по-разному. Но мне не ясно, что (если таковая имеется) специальная обработка делается для этого особого случая, или почему это особый случай вообще.
РЕДАКТИРОВАТЬ: Похоже, что этоделает Работа:
return [ptr = static_cast<decltype(this)>(this)]() { ptr->foo(); };
Это не имеет смысла для меня, потому чтоdecltype
(В отличие отauto
) выводитименно так тип его аргумента, поэтомуstatic_cast
на самом деле не должно влиять на что-либо.
РЕДАКТИРОВАТЬ 2,3,4: Вот полный список выражений, которые я пробовал с обоими компиляторами, с комментариями, указывающими, какой компилятор (ы) принимает каждое выражение:
[this]() { this->foo(); }; // Both: work
[ptr = this]() { ptr->foo(); }; // GCC fails
[ptr = static_cast<decltype(this)>(this)]() { ptr->foo(); }; // Both: works (!!!)
[ptr(this)]() { ptr->foo(); }; // GCC fails
[ptr{this}]() { ptr->foo(); }; // GCC works (!!!!!!!!), Clang doesn't work (infers initializer list)
[ptr = {this}]() { ptr->foo(); }; // Both: fail (infers initializer list)
[ptr = &*this]() { ptr->foo(); }; // Both: work
[ptr = &*(this)]() { ptr->foo(); }; // Both: work
За[ptr{this}]
Моя версия Clang (предварительная версия 3.7) предупреждает, что интерпретация изменится; в настоящее время он выводит список инициализаторов, но, вероятно, более поздние версии будут (или уже делают) выводить типthis
в соответствии с новымauto
правила от N3922.
Меня шокирует, что GCC разрешает[ptr{this}]
но нет[ptr(this)]
, У меня нет объяснения этому.