3

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

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

4

2 回答 2

3

我们可以做一个更简单的例子,它既不能在 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纯右值表达式,其值是调用该函数的对象的地址。

您不能对纯右值进行左值引用,因此会出现错误 - 在这种情况下,gcc 比 clang 解释得更好:

A*&错误:从类型的右值对类型的非常量引用的初始化无效A*

如果我们重写call为采用 aconst T&或 a T&&,则两个编译器都接受该代码。

于 2015-02-05T14:44:55.443 回答
1

这没有用 gcc-4.6 为我编译,所以似乎 gcc-4.8 是发生回归的地方。看来您想要的是A1通过普遍参考,即:PImpl(A1 && a1). 这为我编译了 gcc-4.6、gcc-4.8 和 gcc-4.9。

于 2015-02-05T14:37:23.353 回答