简体   繁体   中英

C++ set iterator error: no match for ‘operator+=’

I am trying to iterate over a set of objects and create a comma-separated string of their names. The commented-out part of the code is supposed to add a comma only if it is not the last one in the set, but it generates the following error:

error: no match for 'operator+=' (operand types are 'std::_Rb_tree_const_iterator' and 'long int') _M_current += -__n;

It works fine if I use a vector instead of a set. What am I doing wrong?

std::string paramList = "";
std::set<Param>::iterator end = params.end();
for (std::set<Param>::iterator it = params.begin(); it != end; ++it) {
  paramList += (*it).name;
  /*if (it != end -1) {
    paramList += ",";
  }*/
}

Only certain categories of iterator allow you to directly perform arbitrary arithmetic, like end-1 .

The iterator of a set permits going forwards and backwards one step at a time, using it++ and it-- . It is true that it - 1 still only traverses one step, but the rule is more general (the language doesn't know that the integer you're providing is just 1 and has no reason to make a special case compared to, say, 42 ).

It is possible to use std::next / std::prev to get this behaviour. This is deliberately more verbose, in order to discourage you from arbitrary arithmetic on the iterator, which is more costly for this kind of iterator than it would be for a simple array-like thing such as a vector.

In this case, std::prev(end) will work for you, and be reasonably idiomatic.

But, if you find yourself writing something like std::next(it, 42) , you probably want to consider improving your algorithm, or using a different container.

Again, the purpose of this restriction is to encourage exactly that thinking.

Another way to write your algorithm might be:

std::string paramList;
std::set<Param>::iterator begin = params.begin(), end = params.end();
for (std::set<Param>::iterator it = begin; it != end; ++it) {
  if (it != begin)
    paramList += ",";

  paramList += (*it).name;
}

Notice how I've flipped the logic to avoid the need to do any arithmetic at all.

I actually usually use a bool flag for this (when my paramList is a stringstream) or just always append a , then shrink paramList by one later (when it's a string) if params was non-empty.

end -1

This part is causing the problem. std::set only has Bidirectional iterators , so it only accepts operator ++ and operator -- on it.

You should use std::prev form <iterator> header instead:

if (it != std::prev(end))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM