C++ Iterator for std::set or std::vector - c++

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

Related

Boost: Vector of Distributions with any

Dear Stack Exchange Experts,
I am trying to set up a class (multivariate distribution function) that stores boost distributions in a std::vector (marginal distribution functions).
While this is possible using boost::variant (see my question: Boost: Store Pointers to Distributions in Vector), I also gave boost::any a try.
The reason being that with variant I have to hard-code the potential types (marginal distributions) when setting up the variant and I wanted to avoid this.
While the different implemented distribution classes do not share a common parent class, there are functions such as boost::math::cdf or boost::math::pdf that can be applied to all distributions, and that I want to apply iterating over the std::vector.
Working with any I produced the code below (which is running fine), but now I have the problem that the function any_cdf needs to check the types.
While I circumvented hard-coding the types when setting up the vector (as for variant) I now need to hard-code the types in the any_cdf function (while the solution with variants can handle the application of the cdf function via a templated visitor function, and thus without any type specifications) which means lots of code to manage, lots of if statements...
However, the logic does not change at all (I cast the type, then apply the cdf function in all if statements), and I wouldn't really care how the function behaves if something other than a boost distribution gets stored in the list.
So is there any chance to have my cake and eat it, meaning not being forced to hard-code the casting type of the distribution in any_cdf (much like a templated visitor function for variants)?
Thanks so much for your help, H.
P.s. if this is not feasible, would I generally be better of with boost::any or boost::variant in this situation?
#include <boost/math/distributions.hpp>
#include <boost/any.hpp>
#include <vector>
#include <iostream>
#include <limits>
//template function to apply cdf
template<class T> T any_cdf(boost::any a, T &x){
//declare return value
T y;
//cast any with hardcoded types
if (a.type() == typeid(boost::math::normal_distribution<T>)){
y = boost::math::cdf(boost::any_cast< boost::math::normal_distribution<T> >(a),x);
} else if (a.type() == typeid(boost::math::students_t_distribution<T>)){
y = boost::math::cdf(boost::any_cast< boost::math::students_t_distribution<T> >(a), x);
} else {
//return NaN in case of failure or do something else (throw exception...)
y = std::numeric_limits<T>::quiet_NaN();
}
return(y);
}
int main (int, char*[])
{
//get distribution objects
boost::math::normal_distribution<double> s;
boost::math::students_t_distribution<double> t(1);
//use any to put just any kind of objects in one vector
std::vector<boost::any> vec_any;
vec_any.push_back(s);
vec_any.push_back(t);
//evaluation point and return value
double y;
double x = 1.96;
for (std::vector<boost::any>::const_iterator iter = vec_any.begin(); iter != vec_any.end(); ++iter){
y = any_cdf<double>(*iter,x);
std::cout << y << std::endl;
}
return 0;
}
Edit: Concerning the comments any seems not to be the easiest/best choice for the task at hand. However for completeness reasons a visitor like implementation for boost::any is discussed at:
visitor pattern for boost::any
Note See my older answer for a discussion of solutions a vector and boost::any vs. boost::variant.
If you don't actually need a dynamic vector of distributions - but just want to apply a statically known list of distributions, you can "get away" with a tuple<> of them.
Now, with a bit (well, a lot) of magic from Phoenix and Fusion, you can "just" adapt the cdf function as a Lazy Actor:
BOOST_PHOENIX_ADAPT_FUNCTION(double, cdf_, boost::math::cdf, 2)
In which case an equivalent extended code sample shrinks to: See it Live On Coliru
int main()
{
typedef boost::tuple<bm::normal, bm::students_t> Dists;
Dists dists(bm::normal(), bm::students_t(1));
double x = 1.96;
boost::fusion::for_each(dists, std::cout << cdf_(arg1, x) << "\n");
std::cout << "\nComposite (multiplication):\t" << boost::fusion::accumulate(dists, 1.0, arg1 * cdf_(arg2, x));
std::cout << "\nComposite (mean):\t\t" << boost::fusion::accumulate(dists, 0.0, arg1 + cdf_(arg2, x)) / boost::tuples::length<Dists>::value;
}
Whoah. That's... hardly 6 lines of code :) And the best part is it's all c++03 compatible already.
Update This is the answer assuming a vector and boost::any vs. boost::variant. If you can use a tuple<> see my other answer
You will end up hardcoding the potential types one way or another.
With variant, you can group and hide the complexities by using visitor:
struct invoke_member_foo : boost::static_visitor<double>
{
template <typename Obj, typename... Args>
double operator()(Obj o, Args const&... a) const {
return o.foo(a...);
}
};
This can be applied to your variant like
boost::apply_visitor(invoke_member_foo(), my_variant);
With boost any, you'd do the typeswitching the boring and manual way:
if (auto dist1 = boost::any_cast<distribution1_t>(&my_any))
dist1->foo();
else if (auto dist2 = boost::any_cast<distribution2_t>(&my_any))
dist2->foo();
else if (auto dist3 = boost::any_cast<distribution3_t>(&my_any))
dist3->foo();
IMO this is clearly inferior for maintainability e.g.
you can't easily extend the type list with an element type that is similar enough to satisfy the same concept and have it support - you'll need to add cases to the type-switch manually (and if you don't - you're out of luck, there is no error and you'll have (silent) bugs. With variant you'll just get a compile error whenever your visitor doesn't handle your type.
this work ^ (the type switching) gets duplicated for each operation that you want to implement across the board. Of course, you can implement the type-switch once, and provide the actual implementation as a functor, but at that moment you'll have implemented the exact equivalent of a static_visitor as I showed for the variant, except with far less efficient implementation.
boost::any can only contain values that are CopyConstructible. Boost variant can even contain references (e.g. boost::variant<dist1_t&, dist2_t&>) and has (some) move-semantics support
In short, boost::any saves on time thought in advance, but all it does is shift the work to the call-sites.
On a positive note, let me share with you an idiom I like, which makes visitors accessible as ordinary free functions. Let's rewrite your any_cdf function for the variant:
namespace detail
{
template <typename T> struct var_cdf_visitor : boost::static_visitor<T> {
template <typename Dist>
T operator()(Dist& dist, T& x) const { return boost::math::cdf(dist, x); }
};
}
template<class T> T var_cdf(VarDist<T> a, T &x)
{
static detail::var_cdf_visitor<T> vis;
return boost::apply_visitor(
boost::bind(vis, ::_1, boost::ref(x)),
a);
}
A full running program can be found Live On Coliru
Demo Listing
#include <boost/bind.hpp>
#include <boost/math/distributions.hpp>
#include <boost/variant.hpp>
#include <iostream>
#include <limits>
#include <vector>
namespace detail
{
template <typename T> struct var_cdf_visitor : boost::static_visitor<T> {
template <typename Dist>
T operator()(Dist const& dist, T const& x) const { return boost::math::cdf(dist, x); }
};
}
template<class T, typename... Dist> T var_cdf(boost::variant<Dist...> const& a, T const& x) {
return boost::apply_visitor(boost::bind(detail::var_cdf_visitor<T>(), ::_1, x), a);
}
int main()
{
namespace bm = boost::math;
typedef std::vector<boost::variant<bm::normal, bm::students_t> > Vec;
Vec vec { bm::normal(), bm::students_t(1) };
//evaluation point and return value
double x = 1.96;
for (auto& dist : vec)
std::cout << var_cdf(dist,x) << std::endl;
}
Actually, though I used a bit of c++11, this could be made even prettier using some c++1y features (if your compiler has them).
And lastly, you can make work for c++03 too; it would just require more time than I currently have to throw at it.
What about:
int main (int, char*[])
{
boost::math::normal_distribution<double> s;
boost::math::students_t_distribution<double> t(1);
typedef std::vector<boost::function<double (double)> > vec_t;
vec_t vec_func;
vec_func.push_back(boost::bind(boost::math::cdf<double>, boost::ref(s), _1));
vec_func.push_back(boost::bind(boost::math::cdf<double>, boost::ref(t), _1));
//evaluation point and return value
double y;
double x = 1.96;
for (vec_t::const_iterator iter = vec_func.begin(); iter != vec_func.end(); ++iter){
y = (*iter)(x);
std::cout << y << std::endl;
}
return 0;
}
Binding argument to a function template can be tricky though.

Object slicing and implicit type conversion

Here's a simplified version of the code I'm using:
namespace BasketNovel {
void Engine::BuryEntities()
{
std::list<Entity*>::iterator iter = p_entities.begin();
while (iter != p_entities.end())
{
if ( (*iter)->getAlive() == false )
{
delete (*iter);
iter = p_entities.erase( iter ); //.erase returns next element
}
else iter++;
}
}
}
I'm getting the following warning from Intel Static Analysis:
BasketNovel.cpp(567): warning #12221: slicing of object "iter" passed as actual argument 2 in call to "std::_List_iterator > > std::list >::erase(std::_List_const_iterator > >)" occurs due to implicit type conversion
I believe that this is basically saying that I'm causing an implicit type conversion in:
iter = p_entities.erase( iter );
(note: I get the same warning even if I change my code to: p_entities.erase( iter++ ); )
I don't quite understand what I'm "slicing" in the above.
What exactly does this mean and how I should go about solving this warning? I'd rather slightly convoluted code than turning off warning messages completely.
What is Object Slicing
Object Slicing is the fact of copying/moving only part of an object, this occurs in general with Base/Derived couples:
struct Base { int i; };
struct Derived: Base { int j; };
void slice() {
Derived d = {};
Base b(d); // b is a "sliced" version of `d`
}
and can lead to nastiness.
Here though, this is just a false positive...
Can it be easier ?
Yes, certainly.
// Place to be deleted values at the end
auto const it = std::partition(p_entities.begin(), p_entities.end(),
[](Entity const* e) { return not e or not e->getAlive(); });
// Delete them
std::for_each(it, p_entities.end(), [](Entity const* e) { delete e; });
// Remove them
p_entities.erase(it, p_entities.end());
It looks like your std::list::erase() method is expecting a std::list<Entity*>::const_iterator and you are passing it an std::list<Entity*>::iterator. This could mean you are compiling the code with C++11 support.
One solution would be to perform the removals in two steps. First, use std::for_each to delete and set to 0 pointers to objects that are not alive.
#include <algorithm>
void deleteDead(Entity* e) {
if (e->getAlive()) return;
delete e;
e = 0;
}
std::for_each(p_entities.begin(), p_entities.end(), deleteDead);
Second, use the [erase-remove idiom](erase-remove idiom to remove elements that are 0.
#include <algorithm>
p_entities.erase(std::remove(p_entities.begin(), p_entities.end(), 0),
p_entities.end() );
After about a month of doing other work, I've realised the answer to the problem was basically in changing
std::list::iterator
to
std::list::const_iterator
The slicing was occurring because .erase() required a const_iterator and made the implicit conversion from iterator.
I'd recommend typedef ing std::list in the header to cover possible future type changes.
I'm keeping MatthieuM.'s answer up though because I think the definition on Object Slicing is far more useful than this answer itself.

Customize an iterator for a wrapped list

I've got a class, memberlist, that contains a std::list of class memberinfo. These represents the peers on a network.
I use the class to add some functionality to the list.
I want to expose some iterators (begin and end) so that outside code can loop through my internal list and read their data. However, I want to have two ways of doing this - one that includes an element for the localhost, and one that doesn't.
What's a good way to do this?
I could put the local node first, then have like begin(showlocal=false) just give the second element instead of the first. Or someone suggested storing a pair of with the bool saying if it's local or not.
Any suggestions on a good way to do this? I'm not too great on advanced STL stuff yet.
Personally I would approach this in a different way and have your memberinfo have a way of telling you if it's local or not.
That way you're not specialising your collection class due to a specialisation of the contained objects. In fact you could just use a standard std::list<memberinfo>.
E.g.
class memberinfo
{
bool IsLocal( ) const;
}
Then you would choose whether you're interested in local members or not while you're iterating through the contained objects.
E.g.
std::list<memberinfo>::iterator it;
std::list<memberinfo> list;
for ( it = list.begin() ; it != list.end() ; it++ )
{
if ( it->IsLocal() )
{
// blah blah blah
}
else
{
// dum dee dum dee
}
}
As I said in comment to your question, I think your first solution is reasonable. However, I'm not sure that giving a parameter to begin is the best approach for discriminating the two cases. The major problem with this is that you cannot use your full collection (including the localhost member) as a range, meaning that you cannot use Boost.Range algorithms or the C++11 range-based for loop.
A simple solution would be to have two different member functions returning the appropriate range, as a pair of iterators. Boost.Range provides a sub_range class, which seems rather appropriate (you want to return a sub-range of the list of members). Here is a sample code using this approach:
#include <boost/range.hpp>
#include <iostream>
#include <string>
#include <vector>
struct MemberInfo
{
std::string name;
};
class MemberList
{
public:
typedef std::vector<MemberInfo>::iterator iterator;
typedef std::vector<MemberInfo>::const_iterator const_iterator;
MemberList()
: members_{MemberInfo{"local"}, MemberInfo{"foo"}, MemberInfo{"bar"}}
{}
boost::sub_range<std::vector<MemberInfo>> all() // includes localhost
{
return boost::sub_range<std::vector<MemberInfo>>(
members_.begin(), members_.end());
}
boost::sub_range<std::vector<MemberInfo> const> all() const
{
return boost::sub_range<std::vector<MemberInfo> const>(
members_.begin(), members_.end());
}
boost::sub_range<std::vector<MemberInfo>> some() // excludes localhost
{
return boost::sub_range<std::vector<MemberInfo>>(
++members_.begin(), members_.end());
}
boost::sub_range<std::vector<MemberInfo> const> some() const
{
return boost::sub_range<std::vector<MemberInfo> const>(
++members_.begin(), members_.end());
}
private:
std::vector<MemberInfo> members_;
};
Now, you can use either all() or some() depending on whether you want to include local or not, and both can be used as ranges:
int main()
{
MemberList ml;
for (MemberInfo mi : ml.all()) { std::cout << mi.name << '\n'; }
for (MemberInfo mi : ml.some()) { std::cout << mi.name << '\n'; }
}
And of course, you can still use iterators as usual:
std::find_if(ml.all().begin(), ml.all().end(), ...);
If you don't want to leak the fact that your members are stored in a std::vector, you can use any_range, which erases the underlying iterator type.

How can I return a copy of a vector containing elements not in a set?

Suppose I have the following two data structures:
std::vector<int> all_items;
std::set<int> bad_items;
The all_items vector contains all known items and the bad_items vector contains a list of bad items. These two data structures are populated entirely independent of one another.
What's the proper way to write a method that will return a std::vector<int> contain all elements of all_items not in bad_items?
Currently, I have a clunky solution that I think can be done more concisely. My understanding of STL function adapters is lacking. Hence the question. My current solution is:
struct is_item_bad {
std::set<int> const* bad_items;
bool operator() (int const i) const {
return bad_items.count(i) > 0;
}
};
std::vector<int> items() const {
is_item_bad iib = { &bad_items; };
std::vector<int> good_items(all_items.size());
std::remove_copy_if(all_items.begin(), all_items.end(),
good_items.begin(), is_item_bad);
return good_items;
}
Assume all_items, bad_items, is_item_bad and items() are all a part of some containing class. Is there a way to write them items() getter such that:
It doesn't need temporary variables in the method?
It doesn't need the custom functor, struct is_item_bad?
I had hoped to just use the count method on std::set as a functor, but I haven't been able to divine the right way to express that w/ the remove_copy_if algorithm.
EDIT: Fixed the logic error in items(). The actual code didn't have the problem, it was a transcription error.
EDIT: I have accepted a solution that doesn't use std::set_difference since it is more general and will work even if the std::vector isn't sorted. I chose to use the C++0x lambda expression syntax in my code. My final items() method looks like this:
std::vector<int> items() const {
std::vector<int> good_items;
good_items.reserve(all_items.size());
std::remove_copy_if(all_items.begin(), all_items.end(),
std::back_inserter(good_items),
[&bad_items] (int const i) {
return bad_items.count(i) == 1;
});
}
On a vector of about 8 million items the above method runs in 3.1s. I bench marked the std::set_difference approach and it ran in approximately 2.1s. Thanks to everyone who supplied great answers.
As jeffamaphone suggested, if you can sort any input vectors, you can use std::set_difference which is efficient and less code:
#include <algorithm>
#include <set>
#include <vector>
std::vector<int>
get_good_items( std::vector<int> const & all_items,
std::set<int> const & bad_items )
{
std::vector<int> good_items;
// Assumes all_items is sorted.
std::set_difference( all_items.begin(),
all_items.end(),
bad_items.begin(),
bad_items.end(),
std::back_inserter( good_items ) );
return good_items;
}
Since your function is going to return a vector, you will have to make a new vector (i.e. copy elements) in any case. In which case, std::remove_copy_if is fine, but you should use it correctly:
#include <iostream>
#include <vector>
#include <set>
#include <iterator>
#include <algorithm>
#include <functional>
std::vector<int> filter(const std::vector<int>& all, const std::set<int>& bad)
{
std::vector<int> result;
remove_copy_if(all.begin(), all.end(), back_inserter(result),
[&bad](int i){return bad.count(i)==1;});
return result;
}
int main()
{
std::vector<int> all_items = {4,5,2,3,4,8,7,56,4,2,2,2,3};
std::set<int> bad_items = {2,8,4};
std::vector<int> filtered_items = filter(all_items, bad_items);
copy(filtered_items.begin(), filtered_items.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
}
To do this in C++98, I guess you could use mem_fun_ref and bind1st to turn set::count into a functor in-line, but there are issues with that (which resulted in deprecation of bind1st in C++0x) which means depending on your compiler, you might end up using std::tr1::bind anyway:
remove_copy_if(all.begin(), all.end(), back_inserter(result),
bind(&std::set<int>::count, bad, std::tr1::placeholders::_1)); // or std::placeholders in C++0x
and in any case, an explicit function object would be more readable, I think:
struct IsMemberOf {
const std::set<int>& bad;
IsMemberOf(const std::set<int>& b) : bad(b) {}
bool operator()(int i) const { return bad.count(i)==1;}
};
std::vector<int> filter(const std::vector<int>& all, const std::set<int>& bad)
{
std::vector<int> result;
remove_copy_if(all.begin(), all.end(), back_inserter(result), IsMemberOf(bad));
return result;
}
At the risk of appearing archaic:
std::set<int> badItems;
std::vector<int> items;
std::vector<int> goodItems;
for ( std::vector<int>::iterator iter = items.begin();
iter != items.end();
++iter)
{
int& item = *iter;
if ( badItems.find(item) == badItems.end() )
{
goodItems.push_back(item);
}
}
std::remove_copy_if returns an iterator to the target collection. In this case, it would return good_items.end() (or something similar). good_items goes out of scope at the end of the method, so this would cause some memory errors. You should return good_items or pass in a new vector<int> by reference and then clear, resize, and populate it. This would get rid of the temporary variable.
I believe you have to define the custom functor because the method depends on the object bad_items which you couldn't specify without it getting hackey AFAIK.

Access Iterator in BOOST_FOREACH loop

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)