I have a BOOST_FOREACH loop to iterate over a list. Unfortunately, I also need to cache an iterator to a particular item.
typedef List::iterator savedIterator;
BOOST_FOREACH(Item &item, list)
{
// stuff...
if (condition)
savedIterator = &item; // this won't work
// do more stuff...
}
Obviously I can do this using a list.begin()..list.end() for loop, but I've grown to like BOOST_FOREACH. Is there a way round this?
This is not possible, as you do not have access to an iterator pointing to the current item inside the loop.
You could fetch an iterator from the list somehow using the current items data but I don't know if this is a good idea to follow, also performance-wise.
I'd suggest you use the solution you already proposed yourself with list.begin() .. list.end(), this is in my opinion the easiest to implement and recognize.
With Boost.Foreach, you're pretty much stuck with the reference to the dereferenced iterator since this is what Boost.Foreach was designed to do: simplify access to the elements in a range. However, if you're just looking for a single element that fits a criteria you might want to try std::find_if():
struct criteria {
template <class T>
bool operator()(T const & element) const {
return (element /* apply criteria... */)? true : false;
}
};
// somewhere else
List::iterator savedIterator =
std::find_if(list.begin(), list.end(), criteria());
It also looks like you want to apply operations on the whole list -- in which case I'll suggest using something like std::min_element() or std::max_element() along with Boost.Iterators like boost::transform_iterator.
struct transformation {
typedef int result_type;
template <class T>
int operator()(T const & element) const {
// stuff
int result = 1;
if (condition) result = 0;
// more stuff
return result;
}
};
// somewhere else
List::iterator savedIterator =
std::min_element(
boost::make_transform_iterator(list.begin(), transformation()),
boost::make_transform_iterator(list.end(), transformation()),
).base();
i kind of wonder why people don't do this:
#define foreach(iter_type, iter, collection) \
for (iter_type iter = collection.begin(); iter != collection.end(); ++iter)
Related
I have a vector of classes, the class has a string name, among other private fields.
I want to implement a void delete(string name) function, which looks for the element based on the string (each class in a vector has a unique name).
However after simple testing, it gives me an error "Cannot increment past the end".
This is my function:
void delete_member(string member_name)
{
int count = 0;
for (auto it = member_list.begin(); it != member_list.end(); ++it, ++count)
if (it->get_name() == member_name)
member_list.erase(member_list.begin() + count);
}
As far as I have searched for an answer, it seems that the iterator shouldn't go past the .end() of the vector.
What is the flaw here? I am using the same loop to iterate over a vector for add_member(Member m) function which works completely fine
The issue is that you erase the element but you do not update the iterators. To avoid dealing with those, it is better to use STL algorithms. The standard usage is as follows
Pre C++20
member.erase(std::remove_if(member.begin(), member.end(), [&](const auto& val)
{
return val.get_name() == member_name;
}), member.end());
In C++20
std::erase_if(member, [&](const auto& val)
{
return val.get_name() == member_name;
});
You are invalidating it when you erase, so later uses of it are undefined, including incrementing and comparing it in the loop test.
You could
for (auto it = member_list.begin(); it != member_list.end(); )
if (it->get_name() == member_name)
it = member_list.erase(it);
else
it++
However there is a standard <algorithm> for this.
auto pred = [&](auto & member){ return member.get_name() == member_name; };
auto new_end = std::remove_if(member_list.begin(), member_list.end(), pred);
member_list.erase(new_end, member_list.end());
In C++20, it will be even easier
auto pred = [&](auto & member){ return member.get_name() == member_name; };
std::erase_if(member_list, pred);
I have a class that uses custom logic to generate some sequence:
class Example{
size_t FirstElement();
size_t NextElement(size_t currentelement);
//When element equals magic number this is
//signalling that the sequence is over.
static size_t MagicNumber =-1;
}
I could consume the sequence as follows:
Example example{};
for(size_t curelement = example.FirstElement;
curelement != Example::MagicNumber;
curelement = example.NextElement(currentelement))
{
//do something with the curelement
}
I would like a solution which makes it similarly easy to consume the sequence, but:
Avoiding the use of the magic number external to Example (i.e. while consuming).
That does not store the currentelement inside the `example' object.
That has perhaps a bit cleaner consumtion code in general?
That does not give substantial performance penalties compared to this code.
EDIT: Example should not return the whole sequence in one go, i.e. as std::vector.
Is there a good alternative. (Based on my (very limited) understanding of iterators, they should be the goto solution here? If so, how to implement such a solution?)
Yes, I would advise you to use iterators. They usually work the same way, like your code:
Example e;
for(auto it = e.begin(); it != e.end(); ++it)
{...}
//Can be simplified to
for(const auto &x : e)
{...}
where begin() will return the iterator pointing to the first element (like Example::FirstElement(). and end() the iterator to the element after the last (This could return your magic number). However...both values should be wrapped in a class and you should not just return integers as iterators.
For further reading I would suggest this and this post.
A for-loop is fine for iterating your class. You just seem to want it to be generic in how it terminates and presumably what the body does. Seems like overkill but this is a solution.
void Consume(Example &example, std::function<bool(Example)> terminateFunc, std::function<void(Example)> bodyFunc)
{
for(size_t curelement = example.FirstElement; !terminateFunc(curelement); curelement = example.NextElement(curelement))
{
bodyFunc(curelement);
}
}
i.e. terminateFunc and bodyFunc are passed in, and can be custom for whatever conditions you require.
auto condition = [](Example e) { return true; /* check if e satisfies some condition; */ };
auto body = [](Example e) { /* do something with e */ };
Consume(example, condition, body);
I have some C++11 code like
std::vector<std::string> names;
std::map<std::string, std::string> first_to_last_name_map;
std::transform(names.begin(), names.end(), std::inserter(first_to_last_name_map, first_to_last_name_map.begin()), [](const std::string& i){
if (i == "bad")
return std::pair<std::string, std::string>("bad", "bad"); // Don't Want This
else
return std::pair<std::string, std::string>(i.substr(0,5), i.substr(5,5));
});
where I'm transforming a vector to a map using std::transform with a lambda function. My problem is that sometimes, as shown, I don't want to return anything from my lambda function, i.e. I basically want to skip that i and go to the next one (without adding anything to the map).
Is there any way to achieve what I'm thinking about? I can use boost if it helps. I want to avoid a solution where I have to do a pre-process or post-process on my vector to filter out the "bad" items; I should only need to look at each item once. Also, my actual logic is a bit more complicated than the if/else as written, so I think it would be nice to keep things encapsulated in this std::transform/lambda model if possible (though maybe what I'm trying to achieve isn't possible with this model).
EDIT: Just to emphasize, I'm looking to perform this operation (selectively processing vector elements and inserting them into a map) in the most efficient way possible, even if it means a less elegant solution or a big rewrite. I could even use a different map data type depending on what is most efficient.
template<class Src, class Sink, class F>
void transform_if(Src&& src, Sink&& sink, F&& f){
for(auto&& x:std::forward<Src>(src))
if(auto&& e=f(decltype(x)(x)))
*sink++ = *decltype(e)(e);
}
Now simply get a boost or std or std experiental optional. Have your f return an optional<blah>.
auto sink = std::inserter(first_to_last_name_map, first_to_last_name_map.begin());
using pair_type = decltype(first_to_last_name_map)::value_type;
transform_if(names, sink,
[](const std::string& i)->std::optional<pair_type>{
if (i == "bad")
return {}; // Don't Want This
else
return std::make_pair(i.substr(0,5), i.substr(5,5));
}
);
My personal preferred optional actually has begin end defined. And we get this algorithm:
template<class Src, class Sink, class F>
void polymap(Src&& src, Sink&& sink, F&& f){
for(auto&& x:std::forward<Src>(src))
for(auto&& e:f(decltype(x)(x)))
*sink++ = decltype(e)(e);
}
which now lets the f return a range, where optional is a model of a zero or one element range.
You can simply have a first/last pass with std::remove_if. E.g.
std::vector<std::string> names;
std::map<std::string, std::string> first_to_last_name_map;
std::transform(names.begin(),
std::remove_if(names.begin(),
names.end(),
[](const std::string &str){
return str=="bad";
}),
std::inserter(first_to_last_name_map,
first_to_last_name_map.begin()),
[](const std::string& i){
return std::pair<std::string, std::string>(i.substr(0,5), i.substr(5,5));
});
Note that remove_if simply shifts the removed items past the iterator it returns.
You can use boost::adaptors::filtered to first filter the vector of the elements you don't want, before passing it to transform.
using boost::adaptors::filtered;
boost::transform(names | filtered([](std::string const& s) { return s != "bad"; }),
std::inserter(first_to_last_name_map, first_to_last_name_map.begin()),
[](std::string const& i) { return std::make_pair(i.substr(0,5), i.substr(5,5)); });
Live demo
Let's say I have this:
struct HoldStuff {
std::vector<StuffItem> items;
std::set<StuffItem, StuffItemComparator> sorted_items;
}
Now, during a refactor, I may have stuff in items or I may have it in sorted_items, but regardless I want to do the same thing with each item. I want to do something like this:
HoldStuff holder; // assume it was filled earlier
auto iter = holder.items.empty() ? holder.sorted_items.begin() :
holder.items.begin();
auto iter_end = holder.items.empty() ? holder.sorted_items.end() :
holder.items.end();
for (; iter != iter_end; ++iter) {
auto& item = *iter;
// Do stuff
}
When I go to compile this, I get errors complaining about incompatible operand types. Surely this is possible, no?
You have two options:
use type-erasure to get a runtime polymorphism on the iterator (any_range or any_iterator)
delegate do_stuff to a function template that takes any kind of iterator
Here is an illustration with code:
#include <vector>
#include <set>
#include <iostream>
#include <boost/range/any_range.hpp>
template<typename Iterator>
void do_stuff(Iterator begin, Iterator end) {}
int main()
{
std::vector<int> items;
std::set<int> sorted_items;
// first option
typedef boost::any_range<int, boost::forward_traversal_tag, int&, std::ptrdiff_t> my_any_range;
my_any_range r;
if(items.empty())
r = my_any_range(sorted_items);
else
r = my_any_range(items);
for (auto& x : r) {
std::cout << x << " ";
}
// second option
// this could also be a lambda and std::for_each
if(items.empty())
do_stuff(sorted_items.begin(), sorted_items.end());
else
do_stuff(items.begin(), items.end());
return 0;
}
Both sides of the ternary operator need to have the same type. In your case, they are different - std::vector<>::iterator and std::set<> iterator. A suitable solution seems to be some sort of a an iterator wrapper, which returns one or another depending on the initial condition.
The errors are correct: auto keyword works during compilation. In an easy way, it just deduces the type of assignment and uses this real type. But decision if it's vector's iterator or set's is made in runtime. So type can not be deduced.
As SergeyA said, I'm wrong here, compiler fail on ?: operator, before auto. But the reason is still the same - it has no idea which type to use for the result.
You should probably use some more generic iterator type + polymorphism, or you can make this function parameterized on type , where T is an iterator type. I would prefer to do it this way:
template<class T> do_stuff(T &c) { for (auto &el : c) { /*Whatever*/ } }
...
if (!items.empty()) {
do_stuff(items);
} else if (!sorted_items.empty()) {
do_stuff(sorted_items);
}
P.S.: It's a conception, I didn't test the code.
auto means the compiler will deduce the type of what follows, at compilation time.
The return type of the ternary conditional operator in this case is what follows the question mark, so it is std::set<StuffItem, StuffItemComparator>::iterator and the compiler tries to cast what follows the column (std::vector<StuffItem>::iterator) to this incompatible type, hence the compiler error.
What you can do is make your item processing code generic, like so:
auto doStuff = [] (StuffItem& item) {
// do stuff with item...
};
if( holder.items.size() )
for_each( holder.items.begin(), holder.items.end(), doStuff );
else if( holder.sorted_items.size() )
for_each( holder.sorted_items.begin(), holder.sorted_items.end(), doStuff );
In my current C++-project I have an STL map which maps integer keys onto objects. An algorithm returns a set of entries. The returned data depends on the algorithm's input and hence cannot be predicted:
class MyClass
{
//...
};
int myAlgorithm(vector<int>::iterator inputIt)
{
// return a key for myMap which is calculated by the current value of inputData
}
int main(int argc, char *argv[])
{
vector<int> inputData;
map<int, MyClass> myMap;
//<fill map with some data>
//<fill inputData>
vector<MyClass> result;
for (vector<int>::iterator it = inputData.begin(); it != inputData.end(); it++)
{
int myMapKey = myAlgorithm(*it);
// count() > 0 means "check whether element exists. Performance can be improved by replacing
// the operator[] and count() calls by map::find(). However, I want to simplify things
// in this example.
if (myMap.count(myMapKey) > 0)
{
// in some cases there is no entry in myMap
result.push_back(myMap[myMapKey]);
}
}
}
As mentioned in the example I can replace map::count() and operator[]-calls with find. The STL-reference says that map::find()'s complexity is logarithmic in size (O(log n)).
I discovered that in most cases the entries in myMap are very close for two sequent entries in the result. Therefore I came to the conclusion that I would achieve better performance if I replaced the map.find() calls by iterators:
map<int, MyClass>::iterator myMapIt = myMap.begin();
for (vector<int>::iterator it = inputData.begin(); it != inputData.end(); it++)
{
int myMapKey = myAlgorithm(*it);
// just increment iterator
while (myMapKey != myMapIt->first)
{
myMapIt++;
// we didn't find anything for the current input data
if (myMapIt == myMap::end() || myMapIt->first > myMapKey)
{
break;
}
}
// I know that I'm checking this twice, but that's not the point of my
// question ;)
if (myMapIt == myMap::end() || myMapIt->first > myMapKey)
{
// probably it would be better to move the iterator back to the position
// where we started searching, to improve performance for the next entry
myMapIt = myMap.begin();
}
else
{
result.push_back(myMapIt.second);
}
}
This concept works but I have a big problem: Depending on the inputData, I have to search forward or backward. Consider that I call the code inside main() multiple times and the inputData changes for these calls. Instead of checking whether to increment or decrement the iterator inside the while-loop, I could decide that before entering the for-loop.
I thought that I'm fine with just switching the map<>::iterator to map<>::reverse_iterator and using rbegin()/rend() instead of begin()/end(). But then I realized that reverse_iterator and iterator have no common base class:
map<int, MyClass>::base_iterator myIt;
if (/* ... */)
{
myMapIt = myMap::begin();
myMapEndIt = myMap::end();
}
else
{
myMapIt = myMap::rbegin();
myMapEndIt = myMap::rend();
}
/* for (...) ... */
That would be great, but there is no base_iterator.
I know a simple workaround for this problem: I just need to copy the whole for-loop and adjust it for both cases:
if (/* ... */)
{
/* for(...) which uses normal iterator in the while-loop */
}
else
{
/* for(...) which uses reverse iterator in the while-loop */
}
Very bad ... Do you know a better solution?
A common base type is unnecessary when the language allows Generic Programming.
What you simply need to realize is that instead of having a long-winded linear functions with several choices along the way, you can have several nested function in which each choice lead to a different call.
Taking your example:
boost::any_iterator start, end;
if (/* ... */) {
start = map.begin(), end = map.end();
} else {
start = map.rbegin(), end = map.rend();
}
// do something with start and end
You can transform the code into the following:
// Define a free-function in the .cpp to help factor common stuff
template <typename FwdIt>
static void dosomething(FwdIt start, FwdIt end) {
// do something with start and end
}
And then inject the call straight into the if/else body:
if (/* ... */) {
dosomething(map.begin(), map.end());
} else {
dosomething(map.rbegin(), map.rend());
}
And one good thing is that you reduce the number of changes of states within your functions and thus their complexity.
Use a templated function. The only place in the Standard library where inheritance is used over templates is IOstreams, as far as I'm aware (and that was a mistake).
template<typename Iterator> ... stuff(Iterator begin, Iterator end) {
// implement loop here
}
if (/*...*/) {
stuff(map.rbegin(), map.rend());
} else {
stuff(map.begin(), map.end());
}
However, I question if you would simply be better off changing to an always O(1) container, like an unordered_map.
You could use templates:
template <typename T>
void myFunction(T start, T end)
{
/* for (...) ... */
}
map<int, MyClass>::base_iterator myIt;
if (/* ... */)
{
myFunction(myMap.begin(), myMap.end());
}
else
{
myFunction(myMap.rbegin(), myMap.rend());
}
From c++14 if you don't want to write template<...> you can let compiler do it for you and use lambda instead create function template.
then call would be like that:
void your_function(auto &some_container, bool from_front) {
auto setter = [&](auto begin, auto end) {
auto no_of_elements_to_change = 3;
for (auto el = begin; el != end; ++el) {
*el = +1000; /// stuff you want to do with last 3 elements
if (--no_of_elements_to_change == 0) {
break;
}
}
};
if (from_front) {
setter(some_container.begin(), some_container.end());
} else {
setter(some_container.rbegin(), some_container.rend());
}
}
With c++20 we will be probably able to do same with std::ranges.