5

我收到以下错误:为“运算符=”与C++ 11的std ::移动暧昧过载,复制和交换成语

[matt ~] g++ -std=c++11 main.cpp -DCOPY_AND_SWAP && ./a.out 
main.cpp: In function ‘int main(int, const char* const*)’: 
main.cpp:101:24: error: ambiguous overload for ‘operator=’ in ‘move = std::move<Test&>((* & copy))’ 
main.cpp:101:24: note: candidates are: 
main.cpp:39:7: note: Test& Test::operator=(Test) 
main.cpp:52:7: note: Test& Test::operator=(Test&&) 

当下面的代码被编译:

#include <iostream> 
#include <unordered_map> 
class Test final { 
public: 
    typedef std::unordered_map<std::string, std::string> Map; 
public: 
    Test(); 
    explicit Test(Map&& map); 
    ~Test(); 
    Test(const Test& other); 
    Test(Test&& test); 
#ifdef COPY_AND_SWAP 
    Test& operator=(Test other); 
#else 
    Test& operator=(const Test& other); 
#endif 
    Test& operator=(Test&& other); 
    size_t Size() const noexcept; 
    friend void swap(Test& lhs, Test& rhs); 
private: 
    friend std::ostream& operator<<(std::ostream& stream, const Test& test); 
private: 
    Map map_; 
}; 
Test::Test() : map_() { 
    std::cerr << "Default constructor called" << std::endl; 
}; 
Test::Test(const Test& other) : map_(other.map_) { 
    std::cerr << "Copy constructor called" << std::endl; 
}; 
Test::Test(Test&& other) : map_(std::move(other.map_)) { 
    std::cerr << "Move constructor called" << std::endl; 
}; 
Test::Test(Map&& map) : map_(std::move(map)) { 
    std::cerr << "Map constructor called" << std::endl; 
}; 
Test::~Test() {}; 
#ifdef COPY_AND_SWAP 
Test& Test::operator=(Test other) { 
    std::cerr << "Copy and swap assignment called" << std::endl; 
    using std::swap; 
    swap(this->map_, other.map_); 
    return *this; 
} 
#else 
Test& Test::operator=(const Test& other) { 
    std::cerr << "Copy assignment called" << std::endl; 
    this->map_ = other.map_; 
    return *this; 
} 
#endif 
Test& Test::operator=(Test&& other) { 
    std::cerr << "Move assignment called" << std::endl; 
    this->map_ = other.map_; 
    other.map_.clear(); 
    return *this; 
} 
size_t Test::Size() const noexcept { 
    return map_.size(); 
} 
void swap(Test& lhs, Test& rhs) { 
    using std::swap; 
    swap(lhs.map_, rhs.map_); 
} 
std::ostream& operator<<(std::ostream& stream, const Test& test) { 
    return stream << test.map_.size(); 
} 
int main (const int argc, const char * const * const argv) { 
    using std::swap; 
    Test::Map map { 
    {"some", "dummy"}, 
    {"data", "to"}, 
    {"fill", "up"}, 
    {"the", "map"} 
    }; 
    std::cout << " map size(): " << map.size() << std::endl; 
    std::cout << "Constructing" << std::endl; 
    Test test(std::move(map)); 
    std::cout << " map.size(): " << map.size() << std::endl; 
    std::cout << "test.Size(): " << test.Size() << std::endl; 
    std::cout << "Copy construction" << std::endl; 
    Test copy(test); 
    std::cout << "copy.Size(): " << copy.Size() << std::endl; 
    std::cout << "Move construction" << std::endl; 
    Test move(std::move(copy)); 
    std::cout << "move.Size(): " << move.Size() << std::endl; 
    std::cout << "copy.Size(): " << copy.Size() << std::endl; 
    std::cout << "Swapping" << std::endl; 
    swap(move, copy); 
    std::cout << "move.Size(): " << move.Size() << std::endl; 
    std::cout << "copy.Size(): " << copy.Size() << std::endl; 
    std::cout << "Swapping back" << std::endl; 
    swap(move, copy); 
    std::cout << "move.Size(): " << move.Size() << std::endl; 
    std::cout << "copy.Size(): " << copy.Size() << std::endl; 
    std::cout << "Copy assignment" << std::endl; 
    copy = test; 
    std::cout << "test.Size(): " << test.Size() << std::endl; 
    std::cout << "copy.Size(): " << copy.Size() << std::endl; 
    std::cout << "Move assignment" << std::endl; 
    move = std::move(copy); 
    std::cout << "move.Size(): " << move.Size() << std::endl; 
    std::cout << "copy.Size(): " << copy.Size() << std::endl; 
return 0; 
} 

g++ -std=c++11 main.cpp && ./a.out编译:

[matt ~] g++ -std=c++11 main.cpp && ./a.out 
map size(): 4 
Constructing 
Map constructor called 
map.size(): 0 
test.Size(): 4 
Copy construction 
Copy constructor called 
copy.Size(): 4 
Move construction 
Move constructor called 
move.Size(): 4 
copy.Size(): 0 
Swapping 
move.Size(): 0 
copy.Size(): 4 
Swapping back 
move.Size(): 4 
copy.Size(): 0 
Copy assignment 
Copy assignment called 
test.Size(): 4 
copy.Size(): 4 
Move assignment 
Move assignment called 
move.Size(): 4 
copy.Size(): 0 

有人能帮助我理解了为什么使用时出现的模糊性在这种情况下复制和交换成语?

回答

7

用于重载解析目的的功能

Test& operator=(Test other); 
Test& operator=(Test&& other); 

是相等的,因为用于转换的隐式转换序列测试和测试& &分别相等。前者并不好,因为直接引用绑定也被认为是身份转换。

当遇到2个同样好匹配的模糊性时,编译器会给出错误。您可能需要:

#ifdef COPY_AND_SWAP 
    Test& operator=(Test other); 
#else 
    Test& operator=(const Test& other); 
    Test& operator=(Test&& other); 
#endif 
+2

+1。解决这个问题的办法是摆脱移动赋值运算符,复制和交换处理rvalues _and_lvalues,这就是更新的点 –

+0

@JonathanWakely tnx。 – TemplateRex

+0

@rhalbersma谢谢你的回答。我明显更理解为什么隐式转换序列是相同的理解rvalues更多 –