g++ 4.9.2 регрессия на проходной ссылке на 'this'

Это минимизированная часть указателя на код реализации:

template<typename T>
class PImpl {
private:
  T* m;
public:

  template<typename A1> 
  PImpl(A1& a1) : m(new T(a1)) {
  }
};

struct A{
    struct AImpl;
    PImpl<AImpl> me;
    A();
};

struct A::AImpl{
    const A* ppub;
    AImpl(const A* ppub)
    :ppub(ppub){}
};
A::A():me(this){}

A a;
int main (int, char**){
    return 0;
}

Он компилируется на G++4.8 и более ранних версиях и работает также. Но компилятор G++4.9.2 вызывает следующие ошибки:

prog.cpp: In constructor 'A::A()':
prog.cpp:24:15: error: no matching function for call to 'PImpl<A::AImpl>::PImpl(A*)'
 A::A():me(this){}
               ^
prog.cpp:24:15: note: candidates are:
prog.cpp:9:5: note: PImpl<T>::PImpl(A1&) [with A1 = A*; T = A::AImpl]
   > PImpl(A1& a1) : m(new T(a1)) {
     ^
prog.cpp:9:5: note:   no known conversion for argument 1 from 'A*' to 'A*&'
prog.cpp:2:7: note: PImpl<A::AImpl>::PImpl(const PImpl<A::AImpl>&)
 class PImpl {
       ^
prog.cpp:2:7: note:   no known conversion for argument 1 from 'A*' to 'const PImpl<A::AImpl>&'

Но это можно исправить небольшим взломом. Если я передам '& * this' вместо 'this', то это приведет к компилируемому состоянию.

Это регрессия G ++ или новая функция стандартов C++, которая устраняет обратную совместимость?

2 ответа

Мы можем сделать более простой пример, который не компилируется ни в g++ 4.9, ни в clang:

template <typename T>
void call(T& ) {  }

struct A { 
    void foo() { call(this); }
};

int main()
{
    A().foo();
}

Это потому this это, из стандарта, [class.this] (§9.3.2):

В теле нестатической (9.3) функции-члена ключевое слово this является выражением prvalue, значением которого является адрес объекта, для которого вызывается функция.

Вы не можете взять lvalue ссылку на prvalue, отсюда и ошибка - которую gcc объясняет лучше, чем clang в этом случае:

ошибка: неверная инициализация неконстантной ссылки типа A*& от значения типа A*

Если мы переписать call либо взять const T& или T&&оба компилятора принимают код.

Это не скомпилировалось для меня с gcc-4.6, поэтому кажется, что в gcc-4.8 произошла регрессия. Кажется, вы хотите взять A1 по универсальной ссылке, то есть: PImpl(A1 && a1), Это компилирует для меня и gcc-4.6, gcc-4.8 и gcc-4.9.

Другие вопросы по тегам