Почему стандарт не рассматривает конструктор шаблона как конструктор копирования? - PullRequest
32 голосов
/ 25 апреля 2019

Вот определение конструктора копирования, [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. Так что кажется, что мой конструктор шаблона является конструктором копирования, по крайней мере, он ведет себя как единица (он вызывается в контексте, где обычно вызываются конструкторы копирования).

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

Ответы [ 3 ]

31 голосов
/ 25 апреля 2019

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

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

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

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

10 голосов
/ 25 апреля 2019

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

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

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, может быть достигнуто либо преобразованием, либо обычным построением, но с учетом возможности копирования из не- Foo объект меняет понятие копирование на копирование, включая преобразование .Но это уже может быть реализовано с помощью существующей схемы (преобразование или создание без копирования).

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

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

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

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

Foo(const Foo&);

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

0 голосов
/ 25 апреля 2019

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

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

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

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

...