尝试调用移动赋值运算符时“operator=”的不明确重载

Ambiguous overload for ‘operator=’ when trying to invoke the move assignment operator

我试图澄清-理解移动语义,为此,我编写了以下代码。我使用原始指针作为数据成员只是为了练习找到所有的危险点,并且还应用了像复制和交换这样的习语。

#include <iostream>
#include <utility>

class Example {
protected:
  int* intPtr;
  
public:
  Example() : intPtr{nullptr} {
    allocate();
    std::cout << "Example() called" << "\n";
  }

  Example(int value) : intPtr{nullptr} {
    allocate();
    assign(value);
    std::cout << "Example(int) called" << "\n";
  }

  ~Example() {
    deallocate();
    std::cout << "~Example called" << "\n";
  }

  Example(const Example& anExample) :
    intPtr{anExample.intPtr ? new int(*anExample.intPtr) : nullptr} {
    std::cout << "Example(const Example&) called" << "\n";
  }

  Example(Example&& anExample) noexcept {
    intPtr = anExample.intPtr;
    anExample.intPtr = nullptr;
    std::cout << "Example(Example&&) called" << "\n";
  }

  Example& operator=(Example&& anExample) noexcept {
    if(this != &anExample){
      intPtr = anExample.intPtr;
      anExample.intPtr = nullptr;
      std::cout << "Move assignment op called" << "\n";
    }
    return *this;
  }
  
  Example& operator=(Example anExample) {
    std::swap(intPtr, anExample.intPtr);
    std::cout << "Copy assignment op called \n";
    return *this;
  }

  void assign(int value) {
    if (intPtr != nullptr && *intPtr!=value) 
      *intPtr = value;
    else {
      std::cout << __FUNCTION__ << ": intPtr is either null, or its memory contains already the value you want.\n";
    }
  }
  
private:
  void allocate() {intPtr = new int{};}

  void deallocate() {delete intPtr;}
 
  friend std::ostream& operator<<(std::ostream& strm, const Example& anExample) {
    return strm << *anExample.intPtr;
  }
  
};

int main() {

  Example ex1;
  std::cout << "----------------" <<std::endl;
  Example ex2{ex1};
  std::cout << "----------------" <<std::endl;
  Example ex3 = ex2; // invokes copy constructor
  std::cout << "----------------" <<std::endl;
  Example ex4;
  std::cout << "----------------" <<std::endl;
  ex4 = ex3; // invokes copy assignement operator
  std::cout << "----------------" <<std::endl;
  Example ex5 = std::move(ex1); // invokes move constructor
  std::cout << "----------------" <<std::endl;
  ex4 = std::move(ex5); // compilation error!
  return 0;
}

最后一行给出如下错误

main.cxx:116:22: error: ambiguous overload for ‘operator=’ (operand types are ‘Example’ and ‘std::remove_reference<Example&>::type’ {aka ‘Example’})
  116 |   ex4 = std::move(ex5);
      |                      ^
main.cxx:36:12: note: candidate: ‘Example& Example::operator=(Example&&)’
   36 |   Example& operator=(Example&& anExample) noexcept {
      |            ^~~~~~~~
main.cxx:45:12: note: candidate: ‘Example& Example::operator=(Example)’
   45 |   Example& operator=(Example anExample) {
      |            ^~~~~~~~

为什么右边的字是std::remove_reference<Example&>::type。我在这里做错了什么以及如何正确调用移动赋值运算符? 欢迎大家发表评论。

Example& operator=(Example anExample) 是一个通用的赋值运算符。它复制左值并移动右值。

如果你想区分复制和移动赋值你需要Example& operator=(const Example & anExample)

或者您可以删除 Example& operator=(Example&& anExample)