Как использовать шаблон копирования и перемещения конструктора и оператора присваивания? - PullRequest
0 голосов
/ 05 января 2019

Рассмотрим следующий код C ++ с моей неудачной попыткой избежать предпочтения не шаблонных конструкторов копирования и перемещения и операторов присваивания :

template<typename T> class A {
public:
    A() { /* implementation here */ }

    // Remove from the overloads the default copy&move constructors and assignment operators
    A(const A&) = delete;
    A& operator=(const A&) = delete;
    A(A&&) = delete;
    A& operator=(A&&) = delete;

    // I want these to be used e.g. by std::vector
    template<typename U> A(const A<U>& fellow) { /* implementation here */ }
    template<typename U> A& operator=(const A<U>& fellow) { /* implementation here */ }

    template<typename U> A(A<U>&& fellow) { /* implementation here */ }
    template<typename U> A& operator=(A<U>&& fellow) { /* implementation here */ }        
};

Однако я получаю следующую ошибку

пытается сослаться на удаленную функцию

при попытке вытолкнуть A элементов в вектор или просто скопировать-конструкцию, например:

A<int> a1{};
A<int> a2(a1);

ОБНОВЛЕНИЕ 1: мне нужны конструкторы копирования и перемещения шаблонов и операторы присваивания, потому что аргумент шаблона действительно просто управляет некоторым кэшированием, поэтому A<T1> можно безопасно назначить A<T2>.

Ответы [ 2 ]

0 голосов
/ 05 января 2019

Минимальный пример конструктора копирования, который делегирует выполнение конструктору шаблона, используя второй неиспользуемый (и по умолчанию) аргумент

#include <iostream>

template <typename T>
struct A
 {
   A()
    { }

   A (A const & a0) : A{a0, 0}
    { }

   template<typename U>
   A (A<U> const &, int = 0)
    { std::cout << "template constructor" << std::endl; }
 };

int main()
 {
   A<int>  a0;
   A<int>  a1{a0};
 }

- РЕДАКТИРОВАТЬ -

ОП просит

А как насчет operator=? Попытка добавить фиктивный параметр приводит к ошибкам компилятора binary 'operator =' has too many parameters and 'operator =' cannot have default parameters

Для operator=() Я предлагаю «делегировать» (не в смысле делегирования конструктора, в данном случае) оба оператора обычному методу; шаблон один.

Что-то как

   template <typename U>
   A & assign (A<U> const &)
    { /* do assignment */ return *this; }

   A & operator= (A const & a0)
    { return assign(a0); }

   template <typename U>
   A & operator= (A<U> const & a0)
    { return assign(a0); }  

Может быть, assign() метод может быть private.

Или лучше, как предлагает Jarod42 (спасибо), напрямую вызывая оператор шаблона из не-шаблона

template <typename U>
A & operator= (A<U> const & a0)
 { /* do assignment */ return *this; }

A & operator= (A const & a0)
 { return operator=<T>(a0); }
0 голосов
/ 05 января 2019

Вы можете сделать компилятор счастливым, объявив удаленный конструктор копирования / оператор присваивания альтернативной сигнатурой, что не приведет к выбору этой перегрузки, но предотвратит генерацию конструктора / оператора присваивания компилятором:

template<typename T> class A
{ public:
    A() { /* implementation here */ }

    // Remove from the implicit declaration of the default copy&move constructors and assignment operators
    A(A volatile const &) = delete;
    A & operator =(A volatile const &) = delete;

    // I want these to be used e.g. by std::vector
    template<typename U> A(A<U> const & fellow) { /* implementation here */ }
    template<typename U> A & operator =(A<U> const & fellow) { /* implementation here */ return *this;}

    template<typename U> A(A<U> && fellow) { /* implementation here */ }
    template<typename U> A & operator =(A<U> && fellow) { /* implementation here */ return *this; }        
};
int main()
{
    A<int> a1{};
    A<int> a2{a1};
    return 0;
}

онлайн-компилятор

15.8.1 Конструкторы копирования / перемещения [class.copy.ctor]
1. Не шаблонный конструктор для class X является конструктором копирования, если его первый параметр имеет тип X&, const X&, volatile X& или const volatile X&, и либо отсутствуют другие параметры, либо все остальные параметры есть аргументы по умолчанию

...