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)], У меня нет объяснения этому.

Ответы на вопрос(1)

Ваш ответ на вопрос