Errors when explicitly deleting move assignment operators

Today I came across this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <string>
#include <vector>
#include <iostream>

struct my_type 
{
    my_type(std::string name_)
            :    name(std::move(name_))
            {}

    my_type(const my_type&)=default;

    my_type(my_type&& other)
    {
            this->swap(other);
    }

    my_type &operator=(my_type other)
    {
            swap(other);
            return *this;
    }

    void swap(my_type &other)
    {
            name.swap(other.name);
    }

private:
    std::string name;
    void operator=(const my_type&)=delete;  
    void operator=(my_type&&)=delete;
};


int main()
{
    my_type t("hello world");
    my_type t1("foo bar");
    t=t1;
    t=std::move(t1);
}


But this generates many compiler errors. However if I get rid of the following lines:

1
2
//void operator=(const my_type&)=delete;  
//void operator=(my_type&&)=delete; 


Then it works. Can someone explain why deleting these operators doesnt work
Last edited on
Despite being deleted, the operators on lines 31 and 32 still participate in overload resolution.

That is, counter-intuitively, the compiler still considers them for the purpose of trying to determine what operator the operations on lines 40 and 41 are using. Hence, the ambiguity: for line 40, two of those three operators are viable. For line 41, all three are viable.

-Albatross
Then how come it doesnt consider the compiler generated ones when you remove the =delete statement?
Because they aren't created. The simply don't exist.
Because there aren't any.

Line 18 declares a valid copy assignment operator using the copy-and-swap idiom. Therefore, the compiler isn't going to implicitly generate its own copy assignment operator for your class.

As for the move assignment operator, one of the requirements for it to be implicitly generated is that the class doesn't have a user-written copy assignment operator (which it does).

And yes, this means the statement on line 41 uses that copy assignment operator.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <string>
#include <vector>

struct my_type {
  my_type(std::string name_) : name(std::move(name_)) {}

  my_type(const my_type&) = default;

  my_type(my_type&& other) { this->swap(other); }

  my_type& operator=(my_type other) {
    std::cout << "COPIED " << other.name << " into " << name << "!\n";
    swap(other);
    return *this;
  }

  void swap(my_type& other) { name.swap(other.name); }

 private:
  std::string name;
  // void operator=(const my_type&)=delete;
  // void operator=(my_type&&)=delete;
};

int main() {
  my_type t("hello world");
  my_type t1("foo bar");
  t = t1;
  t = std::move(t1);
}
COPIED foo bar into hello world!
COPIED foo bar into foo bar!


-Albatross
@TheToaster, despite the name "std::move", the function doesn't perform a move. It performs a cast that matches a move constructor or assignment operator.

It doesn't force a move, just makes it "work" when the recipient (the lvalue "t" in your example) can accept it as a move.

Topic archived. No new replies allowed.