【问题标题】:How to utilize template copy&move constructor and assignment operator?如何利用模板复制&移动构造函数和赋值运算符?
【发布时间】:2019-05-31 17:32:27
【问题描述】:

考虑以下 C++ 代码,我尝试避免 preference of non-template copy&move constructors and assignment operators 失败:

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&lt;T1&gt; 可以安全地分配给A&lt;T2&gt;

【问题讨论】:

  • 复制/移动构造函数永远不是模板。如果您不希望复制/移动构造函数完成工作,也许您可​​以委托。显示实施的哪一部分让您感到困扰;它可能最好放在任何构造函数之外。
  • A&lt;int&gt; a1(); 是一个函数声明(“最烦人的解析...”)而且所有的构造函数都是私有的
  • 而不是 delete 常规的复制/移动构造函数/赋值,将它们转发到模板实现。
  • @Jarod42,你说的转发具体是什么意思?看来这就是我要的 - 如何转发。
  • @SergeRogatch - 您可以在模板构造函数中转发添加未使用的参数(具有默认值)

标签: c++ templates copy-constructor assignment-operator default-constructor


【解决方案1】:

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

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

online compiler

15.8.1 复制/移动构造函数 [class.copy.ctor]
1.class X的非模板构造函数是一个拷贝构造函数,如果它的第一个参数是X&amp;const X&amp;volatile X&amp;const volatile X&amp;类型,或者没有其他参数或者所有其他参数有默认参数

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • operator= 怎么样?尝试添加虚拟参数会导致编译器错误 binary 'operator =' has too many parameters'operator =' cannot have default parameters
    • @SergeRogatch - 答案改进;希望这会有所帮助。
    • @max66: 或return operator=&lt;T&gt;(rhs);.
    • @Jarod42 - 你是对的:有效而且更简单。谢谢。
    猜你喜欢
    • 2012-10-05
    • 1970-01-01
    • 2019-09-29
    • 2011-07-19
    • 1970-01-01
    • 2016-05-19
    • 1970-01-01
    • 2017-05-15
    相关资源
    最近更新 更多