Почему стандарт не рассматривает конструктор шаблона как конструктор копирования?

Вот определение конструктора копирования, [class.copy.ctor/1]:

Нетаблетный конструктор для класса X является конструктором копирования, если его первый параметр имеет тип X &, const X &, volatile X & или const volatile X &, и либо нет других параметров, либо все остальные параметры имеют аргументы по умолчанию ([dcl. fct.default]).

Почему стандарт исключает шаблоны как конструкторы копирования?

В этом простом примере оба конструктора являются конструкторами копирования:

struct Foo {
    Foo(const Foo &); // copy constructor
    Foo(Foo &);       // copy constructor
};

Посмотрите этот похожий пример:

struct Foo {
     Foo() = default;

     template <typename T>
     Foo(T &) {
         printf("here\n");
     }
};

int main() {
    Foo a;
    Foo b = a;
}

В этом примере here будет напечатано. Таким образом, кажется, что мой конструктор шаблона является конструктором копирования, по крайней мере, он ведет себя как единица (он вызывается в контексте, где обычно вызываются конструкторы копирования).

Почему в тексте есть требование "не шаблон"?

Ответ 1

Давай отложим шаблоны на секунду. Если класс не объявляет конструктор копирования, генерируется неявно дефолтный. Он может быть определен как удаленный, но тем не менее по умолчанию.

Шаблон члена не является функцией члена. Участники создаются из него только тогда, когда это необходимо.

Так как же компилятор может узнать из определения класса, нужна ли когда-либо специализация с T = Foo? Не может Но это именно то, на чем нужно основывать решение о том, как обрабатывать потенциальную потребность в неявно дефолтном конструкторе копирования (и конструкторе перемещения). Это становится грязным.

Самый простой подход - исключить шаблоны. Мы всегда будем иметь какой - то конструктор копирования в любом случае, он будет делать правильные вещи ТМ по умолчанию, и будет благоприятствования разрешения перегрузки, поскольку она не инстанцирован из шаблона.

Ответ 2

Почему в тексте есть требование "non- template"?

Учитывая, что это было иначе, и конструкторы копирования могут быть шаблонами. Как конструктор копирования non- не может быть неоднозначным при наличии шаблона конструктора копирования? Учти это:

struct Foo {
   // ctor template: clearly useful and necessary
   template <typename T>
      Foo(const T&) {}

   // copy ctor: same signature! can't work
   template <typename T>
      Foo(const T &) {}
};

Кроме того, построение Foo из объекта, который не является Foo может быть достигнуто либо преобразованием, либо обычной конструкцией, но разрешение на копирование из объекта non- Foo меняет понятие копирования на копирование, включая преобразование. Но это уже может быть реализовано с существующей схемой (преобразование или создание копии non-).

В этом примере здесь будет напечатано. Так что, похоже, мой конструктор шаблона является конструктором копирования

Пример, который вы показываете, не вызывает конструкцию копирования, а является обычной неявной конструкцией. Если вы измените шаблон конструктора на

template <typename T>
Foo(const T &) {
//  ^^^^^
    printf("here\n");
}

тогда Foo b = a; в результате вызывается созданный компилятором конструктор копирования. Обратите внимание, что копия ctor, сгенерированная компилятором, имеет следующую подпись:

Foo(const Foo&);

Это требует добавления const -qualifier к a в Foo b = a; , Исходный шаблон конструктора Foo(T&) в вашем фрагменте лучше подходит, поскольку const -qualifier не добавляется.

Ответ 3

Конструктор копирования имеет форму X (X &) или (X const &), и он будет предоставлен вам компилятором, если вы не объявили его самостоятельно. Не-шаблон приходит сюда, вероятно, из-за проблем, если вы используете шаблонные классы.

Допустим, есть класс шаблона, который имеет конструктор копирования шаблона. Проблема в том, что когда вы создаете экземпляр этого класса, используя другой экземпляр этого класса с тем же типом шаблона, ваш конструктор копирования шаблона не будет вызываться.

Проблема не в том, что ваш шаблон конструктора копирования не совпадает. Проблема заключается в том, что неявный конструктор копирования не является шаблоном функции, а не-шаблоны предпочтительнее специализаций шаблонов, когда речь идет о разрешении перегрузки.

Источник: C++ конструктор копирования шаблона в классе шаблона