【问题标题】:copy constructor as templated member function is ignored复制构造函数作为模板化成员函数被忽略
【发布时间】:2015-10-27 19:33:55
【问题描述】:

赋值运算符可以推导出为成员函数模板的特例吗?

例如,我有一个带有一个 bool 参数的类模板,并且想要实现分配操作,而不管模板参数的任何特定值。

#include <iostream>

template<bool sw>
struct A {
    A() {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }

    template<bool input_sw>
    A & operator = (const A<input_sw> &a) {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        return *this;
    }
};

int main()
{
    A<true> a;
    A<true> b;
    a = b;
}

在上面的代码 sn-p 中,clang 和 gcc 编译的二进制文件没有打印出任何关于赋值的内容——据我所知,默认赋值是在这里生成的,尽管有可能从模板中推断出来。

【问题讨论】:

  • 复制赋值运算符是一个非模板函数。在您的代码中仍然调用了一个隐式生成的复制赋值运算符。它有利于书面函数,因为非模板函数优于模板函数。

标签: c++ templates


【解决方案1】:

他们不打印任何东西是正确的。正在发生的事情是为A&lt;true&gt; 创建了一个隐式 复制赋值运算符,并带有此签名:

A<true>& operator=(const A<true>& );

因此,当我们进行重载决策时,有两个可行的候选者:

A<true>& operator=(const A<true>& );     // implicit copy assignment
A<true>& operator=(const A<input_sw>& ); // [ with input_sw = true ]

两个运算符都采用相同的参数 (const A&lt;true&gt;&amp;),因此从这个角度来看,它们同样是很好的候选者。但是非模板函数比函数模板特化更受欢迎,这使得隐式复制赋值运算符成为最佳可行的候选者。


现在,考虑一个替代方案。如果您以这种方式声明您的操作员模板会怎样:

template<bool input_sw>
A & operator =(A<input_sw> &a) { ... }

也就是说,不是const。这不是一个好的做法,我只是为了说明目的而提出这个。在这种情况下,a=b 的两个候选对象是:

A<true>& operator=(const A<true>& );   // implicit copy assignment
A<true>& operator=(A<input_sw>& );     // [ with input_sw = true ]

现在两个候选人确实采用相同的论点。我们的操作符模板引用了非const。在两个引用的情况下,首选引用最后一个 cv 限定类型的那个,在这种情况下是运算符。删除const,现在您的函数是首选,您将看到打印的内容。

C++ 是最好的。

【讨论】:

  • 我想,明确删除默认赋值运算符不会有帮助吗?是否可以从重载决议中删除默认的?
  • @AlexanderSergeev 否。如果存在隐式赋值运算符,它将被默认或删除。
  • @AlexanderSergeev 将赋值逻辑放在模板化的成员函数中,并将两个运算符重定向到它。或者你可以设计这个类,使得默认的赋值运算符确实是正确的?
  • @NeilKirk 是的,重定向到通用实现是一种选择,但我只是想使用尽可能少的实用程序代码/功能的解决方案;由于资源管理(深拷贝等),默认生成的运算符不正确。
  • @AlexanderSergeev 您可以使用智能指针和容器为您执行深度复制,然后默认生成的将自动工作。
猜你喜欢
  • 1970-01-01
  • 2011-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-12
  • 1970-01-01
  • 2020-04-11
  • 1970-01-01
相关资源
最近更新 更多