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

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

Related

Insert new pair in std::map<CString, CString>

I have two lists and a name to find. If the name to find is not in the first list then it might be in the second list with a slightly different format. Conversion function between the two formats are given.
std::map<CString, CString>* convertedNames;
BOOL CSome::SeekNameWithConversion(std::set<CString> names, CString nameToFind)
{
for (auto it = names.begin(); it != names.end(); ++it)
{
if (nameToFind.Compare(*it) == 0) return true;
auto convertedIt = convertedNames->find(*it);
if (convertedIt != convertedNames->end() &&
nameToFind.Compare(convertedIt->second) == 0)
return true;
CString justConvertedName = ConvertToTheOtherFormat(nameToFind);
convertedNames->insert(*it, justConvertedName); // Error here
return nameToFind.Compare(justConvertedName) == 0;
}
}
The error which appears is:
error C2675: unary '++':
'ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<_CharType>>>' does
not define this operator or a conversion to a type acceptable to the
predefined operator
I would like to know why the operator ++ is involved here and then how should I treat this error.
Most of the various insert functions of std::map require an iterator. Instead, you pass the pointed-to-object, (which is a CString, I suppose):
convertedNames->insert(*it, justConvertedName);
^^^
this is a CString, not a std::map<CString,CString>::iterator
If you want to insert a key-value pair, use the map's value_type instead which is basically a std::pair made up of key and value:
convertedNames->insert(std::make_pair(*it, justConvertedName));
The first argument to map::insert is an iterator, not a CString. Internally, the method is trying to increment the iterator. This apparently makes a call to operator++. You don't need to use this insert overload. It's intended to improve performance when you know a position close to where the element will be inserted. Just call convertedNames->insert(std::make_pair(*it, justConvertedName)) instead.
So the first thing to understand is that templates are always fully implemented in the header, as any classes required are built with that object (just think if the std lib had all possible std::vector implementations built in!)
This means that the implementation of the template is exposed - and in this case, there's a ++ somewhere there. If you take the whole error printed (it'll be quite a few more lines) you may even be told which parameter you've got wrong.
In any case, we can see that *it is clearly going to be a CString, but I'd guess that this
... convert to the other format
is probably not returning what you think

Trouble using iterator on a list of objects

So I have a class called symbol, which is made up of 4 strings which are all public. I created a list of these and I want to do a look ahead on this list. This is what I have so far. I looked up the iterator methods and it says it supports the + operator but I get an error for this.
bool parser::parse(list<symbol> myList){
//Will read tokens by type to make sure that they pass the parse
std::list<symbol>::const_iterator lookAhead = myList.begin();
if ((lookAhead + 1) != myList.end)
lookAhead++;
for (std::list<symbol>::const_iterator it = myList.begin(); it != myList.end(); ++it){
if (it->type == "") {
}
}
return true;
}
I get an error when trying to add 1 to lookAhead. What are some good ways of creating a look ahead for a list?
Thanks,
Binx
A linked list does not support random access iterators, i.e. you cannot add an integer to its iterators.
Use std::next(lookAhead) to get the next iterator instead, or std::advance(lookAhead, 1). These functions know what kind of iterator is being passed, and will use a random seek if possible (e.g. with std::vector's random-access iterators), or manually advance (with a loop in the case of std::advance()) otherwise, as in this case.
Be careful advancing on iterators unconditionally, though -- advancing past end() is undefined!
You can read more about the different categories of C++ iterators here.
Side note: You're copying the entire list when it's passed in, since you're passing it by value. You probably want to pass it by reference instead (list<symbol> const& myList). You can also simplify your code using the C++11 auto keyword, which deduces the type automatically from the type of the expression that initializes the variable:
bool parser::parse(list<symbol> const& myList){
// Will read tokens by type to make sure that they pass the parse
auto lookAhead = myList.begin();
if (lookAhead != myList.end() && std::next(lookAhead) != myList.end())
++lookAhead;
for (auto it = myList.begin(); it != myList.end(); ++it){
if (it->type == "") {
}
}
return true;
}

Difference in behaviour of list<int>::iterator and vector<int>::iterator

I have a std::list<int> and a std::vector<int>. I want to remove even elements from them, and duplicate odd element in them.
I've two different functions for both of them:
Vector:
std::vector<int> vec_remove_even_duplicate_odd(std::vector<int> target) {
std::vector<int>::iterator begin = target.begin();
while (begin != target.end()) {
if (*begin % 2 == 0) {
begin = target.erase(begin);
} else {
begin = target.insert(begin, *begin);
begin += 2;
}
}
return target;
}
This works fine. But the same function for std::list<int> shows error at the line begin += 2:
error: no match for ‘operator+=’ (operand types are ‘std::list<int>::iterator {aka std::_List_iterator<int>}’ and ‘int’)
If I change it to:
begin = begin + 2
it shows the following note:
note: mismatched types ‘const std::reverse_iterator<_Iterator>’ and ‘int’
But, if I change that line to:
++begin;
++begin;
It works fine for list too. So what is it with this behaviour, that I might have missed while reading about containers.
Why is the += operator not defined for std::list<T>::iterator? And why that message for simple + operator? I haven't even created a reverse_iterator?
I'm aware that a vector is a contiguous structure, while a list is not. But how will that matter, given that post-increment is applicable?
Is this issue specific to list only, or some other container also have this issue?
Since std::list is actually a linked list, its iterators provide only the functionality that is trivial to implement in such a data structure; in particular, std::list iterators are so-called bidirectional iterators, not random access iterators, thus they do not provide neither operator+= nor operator+, hence the messages you get.
If in a generic algorithm you need to go forward of n elements, regardless of the computational cost of the operation, you can use std::advance, which will use operator+= for random iterators and repeated application of ++ or -- in the other cases.
By the way, your loop for std::vector doesn't look fine - insertion and removal in a std::vector can invalidate iterators (including those you are using to iterate over your vector); you should change the approach of your algorithm (maybe the simplest thing is just to copy the elements in a separate vector).

what is the better way to write iterators for a loop in C++

For a very simple thing, like for example to print each element in a vector, what is the better way to use in C++?
I have been using this:
for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)
before, but in one of the Boost::filesystem examples I have seen this way:
for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
For me it looks more complicated and I don't understand why is it better then the one I have been using.
Can you tell me why is this version better? Or it doesn't matter for simple things like printing elements of a vector?
Does i != values.end() make the iterating slower?
Or is it const_iterator vs iterator? Is const_iterator faster in a loop like this?
Foo x = y; and Foo x(y); are equivalent, so use whichever you prefer.
Hoisting the end out of the loop may or may not be something the compiler would do anyway, in any event, it makes it explicit that the container end isn't changing.
Use const-iterators if you aren't going to modify the elements, because that's what they mean.
for (MyVec::const_iterator it = v.begin(), end = v.end(); it != end; ++it)
{
/* ... */
}
In C++0x, use auto+cbegin():
for (auto it = v.cbegin(), end = v.cend(); it != end; ++it)
(Perhaps you'd like to use a ready-made container pretty-printer?)
for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)
...vs...
for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
For me [the latter, seen in boost] looks more complicated and I don't understand why is it better then the one I have been using.
I'd say it would look more complicated to anybody who hasn't got some specific reason for liking the latter to the extent that it distorts perception. But let's move on to why it might be better....
Can you tell me why is this version better? Or it doesn't matter for simple things like printing elements of a vector?
Does i != values.end() make the iterating slower?
it_end
Performance: it_end gets the end() value just once as the start of the loop. For any container where calculating end() was vaguely expensive, calling it only once may save CPU time. For any halfway decent real-world C++ Standard library, all the end() functions perform no calculations and can be inlined for equivalent performance. In practice, unless there's some chance you may need to drop in a non-Standard container that's got a more expensive end() function, there's no benefit to explicitly "caching" end() in optimised code.This is interesting, as it means for vector that size() may require a small calculation - conceptually subtracting begin() from end() then dividing by sizeof(value_type) (compilers scale by size implicitly during pointer arithmetic), e.g. GCC 4.5.2:
size_type size() const
{ return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
Maintenance: if the code evolves to insert or erase elements inside the loop (obvious in such a way that the iterator itself isn't invalidated - plausible for maps / sets / lists etc.) it's one more point of maintenance (and hence error-proneness) if the cached end() value also needs to be explicitly recalculated.
A small detail, but here vec must be a typedef, and IMHO it's often best to use typedefs for containers as it loosens the coupling of container type with access to the iterator types.
type identifier(expr)
Style and documentary emphasis: type identifier(expr) is more directly indicative of a constructor call than type identifier = expr, which is the main reason some people prefer the form. I generally prefer the latter, as I like to emphasise the sense of assignment... it's visually unambiguous whereas function call notation is used for many things.
Near equivalence: For most classes, both invoke the same constructor anyway, but if type has an explicit constructor from the type of expr, it will be passed over if = is used. Worse still, some other conversion may allow a less ideal constructor be used instead. For example, X x = 3.14;, would pass over explicit X::X(double); to match X::X(int) - you could get a less precise (or just plain wrong) result - but I'm yet to be bitten by such an issue so it's pretty theoretical!
Or is it const_iterator vs iterator? Is const_iterator faster in a loop like this?
For Standard containers, const_iterator and iterator perform identically, but the latter implies you want the ability to modify the elements as you iterate. Using const_iterator documents that you don't intend to do that, and the compiler will catch any contradictory uses of the iterator that attempt modification. For example, you won't be able to accidentally increment the value the iterator addresses when you intend to increment the iterator itself.
Given C++0x has been mentioned in other answers - but only the incremental benefit of auto and cbegin/cend - there's also a new notation supported:
for (const Foo& foo: container)
// use foo...
To print the items in a vector, you shouldn't be using any of the above (at least IMO).
I'd recommend something like this:
std::copy(values.begin(), values.end(),
std::ostream_iterator<T>(std::cout, "\n"));
You could just access them by index
int main(int argc, char* argv[])
{
std::vector<int> test;
test.push_back(10);
test.push_back(11);
test.push_back(12);
for(int i = 0; i < test.size(); i++)
printf("%d\n", test[i]);
}
prints out:
10
11
12
I don't think it matters. Internally, they do the same thing, so you compiler should optimise it anyway. I would personally use the first version as I find it much clearer as it closely follows the for-loop strucutre.
for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)

Error when using set_union and set_intersection

I have two sets and I'm trying to do a union (I get the same error when doing an intersection). Here is the error:
error C3892: 'std::_Tree_const_iterator<_Mytree>::operator *' : you cannot assign to a variable that is const
Code snippet(if I comment out the line with the --> then the code compiles and my work around way of doing the union works fine):
set<Line *>::iterator it;
set<Line *> * newSet = new set<Line *>();
leftLines = pLeft->getSet();
rightLines = pRight->getSet();
-->it = set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), newSet->begin());
for(it = leftLines->begin(); it != leftLines->end(); it++)
{
newSet->insert(*it);
}
for(it = rightLines->begin(); it != rightLines->end(); it++)
{
newSet->insert(*it);
}
it = newSet->begin();
while(it != newSet->end())
{
result->insert(*it);
it++;
}
I'm sure this is something silly but I'm kind of lost. I think that code snippet should be enough but I can provide whatever else is needed. Thanks.
This is C++, not Java [edit: or .NET]. You almost certainly want to replace (for example):
set<Line *> * newSet = new set<Line *>();
with just:
set<Line *> newSet;
...or, better still, probably just:
set<Line> newSet;
Although it's impossible to say for certain based on the code you've posted, there's a pretty fair chance that your left and right shouldn't be dealing in pointers either -- if they're going to do anything of the sort, a reference probably makes more sense (though, as I said, based on just what you've posted, it's impossible to say for sure).
Once you've done that, you run into a minor problem: a "normal" iterator over a set (or multiset, map or multimap) is really a const_iterator. Once you insert something into an associative container, you're not allowed to change it because that could destroy the collection's invariant (being sorted). If you want to change an existing item, you need to delete if from the contain, make the change, and insert the changed object back into the container. In your case, you're just inserting new items, so you want an insert_iterator.
Since you're not planning on modifying either left or right, you might as well treat them as const as well:
std::set_union(left.cbegin(), left.cend(),
right.cbegin(), right.cend(),
std::inserter(newSet, newSet.end()));
If you decide to simulate set_union on your own, you can do something like this:
std::set<Line> newSet(left.cbegin(), left.cend());
std::copy(right.cbegin(), right.cend(), std::inserter(newSet, newSet.end()));
Edit:
Instead of passing around pointers to containers, you normally want to pass around iterators into the containers. For example, to print out the contents, you apparently now have something like:
void print_data(std::vector<Line *> const *data) {
for (int i=0; i<data->size(); i++)
std::cout << *(*data)[i] << "\n";
}
It probably has more formatting and such, but for the moment we'll ignore those details and assume it's this simple. To write the data directly from a container of your choice, you normally want a template that will accept iterators of an arbitrary type:
template <class inIt>
void print_data(inIt begin, inIt end) {
while (begin != end)
std::cout << *begin++ << '\n';
}
We can, however, go a step further than that, and specify the output as an iterator as well:
template <class inIt, class outIt>
void print_data(inIt begin, inIt end, outIt dest) {
while (begin != end) {
*dest++ = *begin++;
*dest++ = '\n';
}
}
You could go one more step, and allow the user to specify the delimiter to be used between the items, instead of always using '\n', but at that point, you'd just be duplicating something what's already in the standard library -- a combination of std::copy and an std::ostream_iterator, which is how you probably want to deal with this in reality:
std::copy(newSet.begin(), newSet.end(),
std::ostream_iterator<Line>(std::cout, "\n"));
Note, however, that as far as the standard library cares, an ostream_iterator is just another iterator. If you're just going to print out the union of left and right, you can skip even creating a set to hold that union, and just print it out directly:
std::set_union(left.cbegin(), left.cend(),
right.cbegin(), right.cend(),
std::ostream_iterator<Line>(std::cout, "\n"));
The fact that an ostream_iterator writes to a file instead of putting things into a normal collection is entirely irrelevant to the standard library. It has a few classes of iterators, and can write output to any iterator that models the correct class.
Now, I may be jumping the gun, so to speak -- maybe need to do other processing on the data before you write it to the console. My point isn't that you necessarily have to write the union directly to standard output, but just that you don't necessarily have to write it to some other collection before you print it out.
set iterators aren't output iterators. Use this:
set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), inserter(*newSet, newSet->begin()));
Also, why're you filling newSet? Leave it as is after the union/intersection or the union/intersection will be pointless.
set<Line *>::iterator it;
set<Line *> newSet; // No need to `new` this
leftLines = pLeft->getSet();
rightLines = pRight->getSet();
set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), inserter(newSet, newSet.begin()));
// Assuming you really need the below code - you could likely just make an inserter directly on `result` instead of the copying.
it = newSet.begin();
while(it != newSet.end())
{
result->insert(*it);
it++;
}