You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

类仅含模板化移动赋值运算符时为何支持拷贝赋值操作?

问题核心原因解释

这是C++标准的明确规定导致的差异,具体可拆解为三个核心要点:

  1. 只有非模板的特殊成员函数才会触发默认函数删除规则
    C++标准中对移动赋值运算符的定义是:非模板、参数为当前类类型的右值引用(或带const/volatile修饰的右值引用)的成员赋值运算符。
    类A中的赋值运算符是模板函数,不属于标准定义的移动赋值运算符范畴,因此不会触发「用户声明移动操作则删除默认拷贝操作」的规则,编译器会正常为类A隐式生成默认的拷贝赋值运算符。你执行a2 = a1时,模板也会实例化为A& operator=<A&>(A& theOther)匹配左值赋值场景,因此不会报错。
  2. 类B的报错完全符合标准预期
    类B中声明的是非模板的移动赋值运算符,符合标准对移动赋值运算符的定义,因此编译器会将隐式生成的拷贝赋值运算符标记为删除。b2 = b1 中b1是左值,无法匹配移动赋值的右值引用参数,只能调用被删除的拷贝赋值运算符,因此触发编译报错。
  3. 模板化赋值运算符的合规性与隐患
  • 语法层面这种写法是完全合规的,但工程层面不推荐无约束使用。
  • 这类模板化赋值运算符存在不少隐性问题:比如它会参与所有赋值场景的重载决议,可能在你预期调用拷贝/移动赋值的时候,实例化出更匹配的模板版本;如果传入非A类型的参数,还可能因为访问私有成员、类型不匹配等问题产生意料之外的编译错误。如果确实需要使用这类模板赋值,建议配合std::enable_if添加类型约束,限制模板参数只能为当前类类型。

附复现代码与报错信息

#include <iostream>
#include <string>

class A
{
public:
    template <class Type>
    Type& operator=(Type&& theOther)
    {
        text = std::forward<Type>(theOther).text;

        return *this;
    }

private:
    std::string text;
};

class B
{
public:
    B& operator=(B&& theOther)
    {
        text = std::forward<B>(theOther).text;

        return *this;
    }

private:
    std::string text;
};

int main()
{
    A a1;
    A a2;
    a2 = a1;

    B b1;
    B b2;
    b2 = b1;

    return 0;
}

编译报错信息:

..\src\Main.cpp: In function 'int main()':
..\src\Main.cpp:41:7: error: use of deleted function 'B& B::operator=(const B&)'
   41 |  b2 = b1;
      |       ^~
..\src\Main.cpp:19:7: note: 'B& B::operator=(const B&)' is implicitly declared as deleted because 'B' declares a move constructor or move assignment operator
   19 | class B
      |       ^
mingw32-make: *** [Makefile:419: Main.o] Error 1

内容的提问来源于stack exchange,提问作者Benjamin Bihler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 01:18:02