Одна распространенная ошибка в том, что конструктор шаблона или оператор присваивания не будут подавлять сгенерированный компилятором один:
template <typename T>
class A {
public:
template <typename S>
A(A<S> const &);
template <typename S>
A & operator=(A<S> const &);
private:
int * i;
};
Хотя эти функции выглядят как конструктор копирования и оператор присваивания копии, компилятор не видит его таким образом и все равно генерирует неявные версии. В результате любые действия, выполняемые этими функциями (например, глубокое копирование члена), не будут выполняться, когда объект копируется или назначается из того же типа:
void foo (A<int>);
void bar () {
A<int> a1;
foo (a1); // Implicitly generated copy ctor called
A<long> a2;
foo (a2); // Template ctor called.
A<int> a3;
a3 = a1; // Implicitly generated copy assignment operator called
a3 = a2; // Template assignment operator called
}
Причиной такого поведения является специальное правило разрешения перегрузки (13.3.3):
Учитывая эти определения, жизнеспособный
функция F1 определена как лучшая
функция, чем другая жизнеспособная функция
F2 если для всех аргументов i, ICSi (F1)
не хуже, чем последовательность преобразования
ICSi (F2), а затем
[...]
- F1 - не шаблонная функция
и F2 - это шаблон функции
специализация или, если не так,
В приведенных выше примерах разрешение перегрузки видит две функции с одинаковой сигнатурой, одна из которых является шаблоном. Не шаблонная функция (неявно сгенерированный конструктор копирования / оператор копирования) побеждает и так называется.