5

Tôi nhận được lỗi sau:quá tải nhập nhằng cho 'operator =' với C++ 11 std :: di chuyển và sao chép và hoán đổi thành ngữ

[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&&) 

Khi đoạn mã sau được biên soạn:

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

khi biên soạn với 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 

có thể ai đó giúp tôi hiểu tại sao sự nhập nhằng xảy ra khi sử dụng sao chép và hoán đổi thành ngữ trong trường hợp này?

Trả lời

7

cho các mục đích giải quyết tình trạng quá tải chức năng

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

đều bình đẳng, bởi vì trình tự chuyển đổi ngầm dùng để chuyển đổi để thử nghiệm và thử nghiệm & &, tương ứng, đều bình đẳng. Trước đây không tốt hơn, bởi vì ràng buộc tham chiếu trực tiếp cũng được coi là một chuyển đổi nhận dạng.

Khi đối mặt với sự mơ hồ của 2 kết quả phù hợp tốt, trình biên dịch đưa ra lỗi. Bạn có thể muốn điều này:

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

+1. Và giải pháp cho vấn đề là loại bỏ nhà điều hành chuyển nhượng, bản sao và trao đổi xử lý các giá trị _and_ lvalues, đó là điểm –

+0

@JonathanWakely tnx, được cập nhật. – TemplateRex

+0

@rhalbersma Cảm ơn câu trả lời. Tôi rõ ràng có nhiều hiểu hơn về lý do tại sao các chuỗi chuyển đổi tiềm ẩn giống nhau bằng cách hiểu giá trị hơn –

Các vấn đề liên quan