如何使用模板复制和移动构造函数和赋值运算符?

How to utilize template copy&move constructor and assignment operator?

本文关键字:移动 构造函数 赋值运算符 复制 何使用      更新时间:2023-10-16

请考虑以下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);

UPDATE1:我需要模板复制和移动构造函数和赋值运算符,因为模板参数实际上只是控制一些缓存,因此A<T1>可以安全地分配给A<T2>

您可以通过声明带有替代签名的已删除复制构造函数/赋值运算符来使编译器满意,这不会导致选择此重载,但会阻止编译器生成构造函数/赋值运算符:

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& ,并且没有其他参数,或者所有其他参数都有默认参数

复制

构造函数的最小示例,该构造函数使用第二个未使用(和默认)参数将执行委托给模板构造函数

#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};
 }

--编辑--

OP问

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); }