В связи с этот пост, пожалуйста, объясните это поведение:
#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.)
Подпись неявного конструктора копирования для класса 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
не будет иметь неявного конструктора копирования.
Да, это поведение четко определено стандартом в 12.8 / 8:
Неявно объявленный конструктор копирования для класса
X
будет иметь формуX::X(const X &)
если [… условия, в которых это имеет смысл …], иначе [оно] будет иметь видX::X(X &)
,
И действительно, если ваш класс A
имеет члена B
константная форма невозможна, и, таким образом, неявно объявленный конструктор копирования принимает неконстантную форму.
Обратите внимание, что шаблонный конструктор никогда не является копия конструктор.