конкурирующие конструкторы неявных и шаблонных копий

В связи с этот пост, пожалуйста, объясните это поведение:

#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.)

3

Решение

Подпись неявного конструктора копирования для класса 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 не будет иметь неявного конструктора копирования.

4

Другие решения

Да, это поведение четко определено стандартом в 12.8 / 8:

Неявно объявленный конструктор копирования для класса X будет иметь форму X::X(const X &) если [… условия, в которых это имеет смысл …], иначе [оно] будет иметь вид X::X(X &),

И действительно, если ваш класс A имеет члена Bконстантная форма невозможна, и, таким образом, неявно объявленный конструктор копирования принимает неконстантную форму.

Обратите внимание, что шаблонный конструктор никогда не является копия конструктор.

3

По вопросам рекламы [email protected]