G++ 4.9.2 传递引用'this'时的回归

g++ 4.9.2 regression on pass reference to 'this'

本文关键字:this 回归 引用 G++      更新时间:2023-10-16

这是指向实现代码的指针的最小化部分:

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++标准功能消除了向后兼容性?

我们可以制作一个更简单的例子,既不在g++4.9上编译,也不在clang:上编译

template <typename T>
void call(T& ) {  }
struct A { 
    void foo() { call(this); }
};
int main()
{
    A().foo();
}

这是因为从标准来看,this是[类别this](§9.3.2):

在非静态(9.3)成员函数的主体中,关键字thisprvalue表达式,其值是为其调用函数的对象的地址。

您不能将左值引用到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。