5

Ich erhalte die folgende Fehlermeldung:mehrdeutig Überlastung für 'Operator =' mit C++ 11 std :: bewegen und kopieren und Swap-Idiom

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

Wenn der folgende Code kompiliert wird:

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

wenn mit g++ -std=c++11 main.cpp && ./a.out zusammengestellt:

[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 

Könnte mir jemand helfen zu verstehen, warum die Mehrdeutigkeit auftritt, wenn die Verwendung von Kopieren und tauschen Sie Idiom in diesem Fall?

Antwort

7

zum Zweck der Überladungsauflösung der Funktionen

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

gleich sind, weil die impliziten Konvertierungssequenzen verwendet zu konvertieren & zu testen und zu Test-& jeweils gleich sind. Ersteres ist nicht besser, weil die direkte Referenzbindung auch als Identitätskonvertierung betrachtet wird.

Wenn die Mehrdeutigkeit von 2 gleich gute Übereinstimmungen konfrontiert wird, gibt der Compiler einen Fehler. Sie möchten das wahrscheinlich:

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

+1. Und die Lösung des Problems ist, den Verschiebungszuweisungsoperator loszuwerden, der Copy-and-Swap behandelt rvalues ​​_and_ lvalues, das ist der Punkt –

+0

@ JonathanWakely tnx, aktualisiert. – TemplateRex

+0

@rhalbersma Danke für die Antwort. Ich habe offensichtlich mehr darüber zu verstehen, warum die impliziten Konvertierungssequenzen gleich sind, indem man Rvalues ​​mehr versteht. –