3

关于这篇文章,请解释这种行为:

#include <stdio.h>

struct B { B(B&) { } B() { } };
struct A {
  template<typename T>
  A(T&){ printf("A(T&)\n"); }
  A() { }
//  B b; // when this is uncommented, output changes 
  int i;
};

int main() {
  A a;
  A b(a);

// B b; commented:
// template wins:
//   A<A>(A&)  -- specialization
//   A(A const&); -- implicit copy constructor
// (prefer less qualification)

// B b; uncommented:
// implicit copy constructor wins:
//   A<A>(A&)  -- specialization
//   A(A&); -- implicit copy constructor
// (prefer non-template)

  printf("\nA\n");
  A const a1;
  A b1(a1);

// B b; commented:
// implicit copy constructor wins: 
//   A(A const&) -- specialization
//   A(A const&) -- implicit copy constructor
// (prefer non-template)

// B b; uncommented:
// template wins:
//   A(A const&) -- specialization
// (implicit copy constructor not viable)
}

B b 时输出变化;未注释。

显然,隐式复制构造函数从取消注释A(A const&)变为A(A &)何时B b;。为什么?当我更改B(B&){}B(const B&){}复制构造函数时,更改回A(A const&). 现在编译器对 的形式参数感到A()满意const? 这跟标准有关系吗?(我使用的是 gcc 4.2.4。)

4

2 回答 2

4

A类的隐式复制构造函数的签名A(const A&)在可行的情况下。当您取消注释该B b;行时,此复制构造函数不可行,因为复制构造函数B需要一个非常量输入参数。

// Illegal implicit copy constructor
A::A(const A& a) :
b(a.b),  // This line would be illegal because a.b is const
i(a.i)
{
}

在这种情况下,隐式复制构造函数也是非常量版本:A(A&);.

// Legal implicit copy constructor
A::A(A& a) :
b(a.b),  // Fine: a.b is now non-const
i(a.i)
{
}

这就是B b;在类定义中取消注释会更改隐式复制构造函数并因此更改程序行为的原因。

编辑:不直接相关,但为了完整起见:如果B没有可访问的复制构造函数(因为它被声明private或删除),A则不会有隐式复制构造函数。

于 2012-12-17T12:12:27.003 回答
3

是的,这种行为在 12.8/8 标准中得到了很好的定义:

类的隐式声明的复制构造函数X将具有X::X(const X &)if [... conditions where this s sense ...] 的形式,否则 [it] 将具有形式X::X(X &)

事实上,如果你的类A有一个 member B,那么 const 形式是不可能的,因此隐式声明的复制构造函数采用非常量形式。

请注意,模板化构造函数永远不是复制构造函数。

于 2012-12-17T12:13:35.573 回答