C++ Templates – Copy Assignment Operator Implicitly Deleted

c++templates

I'm trying to use copy assignment in the following case.

There're two template classes, list map and xpair.

template <typename Key, typename Value, class Less=xless<Key>>
class listmap {
public:
   using key_type = Key;
   using mapped_type = Value;
   using value_type = xpair<const key_type, mapped_type>;     //value_type
...
}

template <typename First, typename Second>
struct xpair {
   First first{};
   Second second{};
   xpair(){}
   xpair (const First& first, const Second& second):
           first(first), second(second) {}
};

In the main.cpp, I tried to write,

using commend = string;
using str_str_map = listmap<string,string>;
using str_str_pair = str_str_map::value_type;    //value_type, to be replaced
using commend_pair = xpair<commend, str_str_pair>;

int main(...) {
   commend_pair cmd_pair;
   str_str_pair newPair ("Key", "value");
   cmd_pair.second = newPair;

   ...
}

It gives me an error saying

  object of type 'xpair<const std::__1::basic_string<char>,
  std::__1::basic_string<char> >' cannot be assigned because its copy
  assignment operator is implicitly deleted

If I replace

using str_str_pair = str_str_map::value_type;

to

using str_str_pair = xpair<string, string>;

Everything works fine. Why is that? Shouldn't value_type = xpair<string, string>?

Best Answer

I don't see where newPair is declared, but the error message seems like enough.

Why this fails: If either element in the pair is const, the assignment operator for that element is itself deleted. You couldn't assign to a const string but that's exactly what you're asking it to do when you assign to pair<const string, T>. To simplify the example

std::pair<const int, int> p(0, 0);
p.first = 1; // no, can't assign to p.first
p = std::pair<const int, int>(1, 2); // no, requires assigning to p.first

Why maps have const key types: map containers organize their elements based of the keys. If you changed a key, the map wouldn't be able to find it anymore. Consider:

std::map<std::string, int> m = { ... };
auto it = m.find(k);
it->first = "a different value";

Since a std::map for example, is internally organized as a red-black tree, changing the key safely would require a reorganization of the node. However in this example you're operating directly on the pair in the node. Changing the key would require removing the pair from m, then putting it back in with a changed key.

Related Question