I'd like to use the boost::transform_iterator together with boost::bind to return the result of a member function.
e.g.
class Foo
{
public:
//...
Bar& getBar();
const Bar& getBar() const;
};
I've got a unary Function object to select the getBar() function
struct getBar: public std::unary_function<Foo&,Bar&>
{
getBar::result_type operator()(getBar::argument_type arg ) const {
return arg.getBar()
}
};
and lets say i've stored several Foo objects inside a std::vector and Im using a tranform_iterator like that
int main()
{
typedef std::vector<Foo> VEC;
typedef boost::transform_iterator<getBar,VEC::iterator> iterator;
VEC vec;
vec.push_back( Foo ());
iterator i( vec.begin() );
//...
Bar = *i;
return 0;
};
But if i want to use boost::bind instead of the getBar functor how would i do that. I'm not sure which template parameter I would have to pass to the transform_iterator.
EDIT:
the solution with boost::function was a good start but i wasn't completely satisfied so experimented a bit and looked into the return type of boost::mem_fn
typedef boost::transform_iterator<boost::_mfi::mf0<Bar&,Foo>,VEC::iterator> iter;
typedef boost::transform_iterator<boost::_mfi::cmf0<const Bar&,Foo>,VEC::const_iterator> citer;
but this solution has another problem.
because
iter i(v.begin(), boost::mem_fn( &Foo::getBar ));
citer ci(v.begin(), boost::mem_fn( &Foo::getBar ));
leads to the following error
call of overloaded mem_fn(<unresolved overloaded function type>) is ambiguous
the compiler is not able to identify which getBar function is requested and I had to help him a little.
iter i(v.begin(), boost::mem_fn( static_cast<Bar& (Foo::*)()>(&Foo::getBar) ));
citer ci(v.begin(), boost::mem_fn( static_cast<const Bar& (Foo::*)() const >(&Foo::getBar) ));
this is probably not faster than writing a little functor by hand but at least it helped me to understand boost::mem_fn a bit more.
boost::transform_iterator<boost::function<Bar&(Foo&)>,std::vector<Foo>::iterator>
Related
I have two different objects:
struct TypeA {
std::size_t no;
std::string data;
std::string data2;
};
struct TypeB {
std::size_t no;
std::string data;
std::string data2;
std::string data3;
};
They are stored in a std::vector with std::variant
std::vector<std::variant< TypeA, TypeB>> ab;
Now i want to remove all elements were the member no = 0.
Without the std::variant with the vector containing only TypeA I would do it like this:
ab.erase(std::remove_if(ab.begin(), ab.end(),
[](const TypeA& a) { return a.no == 0; }), ab.end());
But how to incorporate the std::variant ? I tried to come up with something with std::visit but i cannot ad it in the predicate of std::remove_if or can I?
Yes, std::visit can help. The functor passed to visit just needs to be able to accept each type of the variant, and the easiest way to do that is with a generic lambda:
ab.erase(
std::remove_if(
ab.begin(),
ab.end(),
[](const auto &v) {
return std::visit(
[](const auto &obj) { return obj.no == 0; },
v);
}),
ab.end());
Here the type of v for the outer lambda is always used as const std::variant<TypeA, TypeB>&, and auto is just more convenient than typing out std::variant<TypeA, TypeB>. But for the inner lambda, it's important that the lambda is generic, because visit will instantiate its template operator() with both TypeA and TypeB.
If you want to access the "same" data member of different types, then these types need to be subclasses of a common polymorphic base class defining this data member.
In your case, however, where TypeA and TypeB are not related, you'll have to make a type-safe access to the respective data member. The solution provided by #aschepler shows this in a generic way using std::visit functor; the following solution is without std::visit (hence not that elegant, but still working):
ab.erase(std::remove_if(ab.begin(), ab.end(),
[](const std::variant< TypeA, TypeB>& v) {
int no;
if (v.index()==0) {
no = std::get<0>(v).no;
} else {
no = std::get<1>(v).no;
}
return no==0;
}), ab.end());
I'm currently looking at some code that uses instances of both of the following types of maps:
std::map<std::string, const Foo>;
std::map<std::string, Foo>;
where the implementation of Foo is not relevant. As a result, all of the functions that take as input an instance of either of these two have two implementations of them: one for the const Foo version and the other for the non-const Foo version.
My question is this: is it possible to create something (like a class derived from std::map, for example) using templates that will allow me to essentially encapsulate both versions of the types above as one?
Edit: I know I can probably use SFINAE to only have to write one version of each of the relevant functions, but I'm wondering if there's a way to implement something a little bit further "upstream."
I apologize if my question doesn't make sense - I'm not exactly sure how to word it in a nice way.
A function that can accept both the const and non const versions of your map could be implemented in this manner:
template <typename T_foo>
T_foo do_something_with_map(std::map<std::string, T_foo> & map)
{
std::cout << map["m"].i_ << std::endl;
return map["m"];
}
int main()
{
std::map<std::string, const Foo> m1;
Foo f1(1);
m1.emplace("m", f1);
std::map<std::string, Foo> m2;
const Foo f2(2);
m2.emplace("m", f2);
auto res1 = do_something_with_map(m1);
auto res2 = do_something_with_map(m2);
}
With an example Foo:
class Foo {
public:
Foo() = default;
Foo(int i)
: i_(i)
{}
int i_;
};
I have a test map with pair of std::string and Person pointer
class MyMap {
public:
void clear() {
std::for_each(people.begin(), people.end(),std::bind1st(std::mem_fun(&MyMap::remove), this));
}
void remove(std::pair<std::string, Person*> p) { delete p.second; }
private:
std::map<name, Person*> people;
};
My question is does for_each pass each Person pair by ref or value? is it worth using my own, this is a bit cleaner.
In addition to that if I want to use boost::bind or std::bind (c++11) instead of bind1st, how would I do it? should this function be like struct having operator() that inherits std::unary_function?
The type of the map is std::map<name, Person*>, but the parameter for the remove function is std::pair<std::string, Person*>. This won't work unless name is typedef for std::string.
The way your remove function is currently defined, you'll make copies of the map's value_type. Change the function signature to:
void remove(std::pair<const std::string, Person *>& p)
// ^^^^^ ^
// key must be const take a reference
To use std::bind instead of std::bind1st
std::for_each( people.begin(),
people.end(),
std::bind( &MyMap::remove, this, std::placeholders::_1 ) );
But if you can use C++11 features, there's no need for std::bind, lambda is much nicer.
std::for_each( people.begin(),
people.end(),
[]( decltype(*people.begin())& p ) { delete p.second; } );
or use a range based for loop
for( auto&& p : people ) {
delete p.second;
}
for_each will call the functor either by-value or by-reference, depending on how you have defined the functor.
For example:
struct Gizmo
{
bool operator() (const Zippy& rhs) const
{
// ...
}
};
This functor is call-by-ref. However:
struct Gizmo
{
bool operator() (Zippy rhs) const
{
// ...
}
};
This one is call-by-value.
In general, templates arguments can be abstract classes, as the program below also shows. But it seems that the compare functor in sort must not be abstract. At least the following does not compile with VC++ 11 and on Oracle Studio 12.
#include <vector>
#include <algorithm>
class Functor
{
public:
virtual bool operator()(int a, int b) const = 0;
};
class MyFunctor: public Functor
{
public:
virtual bool operator()(int a, int b) const { return true; }
};
int _tmain(int argc, _TCHAR* argv[])
{
vector<Functor> fv; // template of abstract class is possible
vector<int> v;
MyFunctor* mf = new MyFunctor();
sort(v.begin(), v.end(), *mf);
Functor* f = new MyFunctor();
// following line does not compile:
// "Cannot have a parameter of the abstract class Functor"
sort(v.begin(), v.end(), *f);
return 0;
}
Now, I wonder whether this is a general property of functor arguments, or does it depend on the STL implementation? Is there a way to get, what I wanted to do?
Functors generally need to be copyable. Polymorphic base classes are generally not copyable, and abstract bases never.
Update: Thanks to the comments by #ahenderson and #ltjax, here's a very simple way to produce a wrapper object that holds your original, polymorphic reference:
#include <functional>
std::sort(v.begin(), v.end(), std::ref(*f));
// ^^^^^^^^^^^^
The result of std::ref is a std::refrence_wrapper which is exactly what you need: A class with value semantics that holds a reference to your original object.
The fact that functors get copied throws off lots of people who want to accumulate something inside the functor and then wonder why the results are off. The functor should really take a reference to an external object. To wit:
Bad! Won't work as you expect; the functor may get copied arbitrarily:
struct Func1 {
int i;
Func1() : i(0) { }
void operator()(T const & x) { /* ... */ }
};
Func1 f;
MyAlgo(myContainer, f);
Good: You provide the accumulator; it's safe to copy the functor:
struct Func2 {
int & i;
Func2(int & n) : i(n) { }
void operator()(T const & x) { /* ... */ }
};
int result;
MyAlgo(myContainer, Func2(result));
As Kerrek has said you can't do it directly:
But one level of indirection and you're OK.
struct AbstractFunctor
{
AbstractFunctor( Functor * in_f ): f(in_f) {}
// TODO: Copy constructor etc.
Functor * f;
bool operator()(int a, int b) const { return (*f)(a,b); }
};
int main()
{
vector<int> v;
Functor * mf = new MyFunctor();
sort(v.begin(), v.end(), AbstractFunctor(mf) );
}
As Kerrek and Michael Anderson said, you can't do it directly. As Michael shows, you can write a wrapper class. But there's also one in std:: :
sort(v.begin(),
v.end(),
std::bind(&Functor::operator(),
mf,
std::placeholders::_1,
std::placeholders::_2) );
Consider:
std::tuple<int , const A&> func (const A& a)
{
return std::make_tuple( 0 , std::ref(a) );
}
Is the std::ref required for writing correct and portable code? (It compiles fine without it)
Background:
If I remove std::ref my code builds fine without any warnings (g++-4.6 -Wall), but doesn't run correctly.
In case of interest the definition of A:
struct A {
std::array<int,2> vec;
typedef int type_t;
template<typename... OPs,typename... VALs>
A& operator=(const std::pair< std::tuple<VALs...> , std::tuple<OPs...> >& e) {
for( int i = 0 ; i < vec.size() ; ++i ) {
vec[i] = eval( extract(i,e.first) , e.second );
}
}
};
One of the example where std::ref is necessary:
void update(int &data) //expects a reference to int
{
data = 15;
}
int main()
{
int data = 10;
// This doesn't compile as the data value is copied when its reference is expected.
//std::thread t1(update, data);
std::thread t1(update, std::ref(data)); // works
t1.join();
return 0;
}
The std::thread constructor copies the supplied values, without converting to the expected argument type (which is reference type in this case, seeupdate()). So we need to wrap the arguments that really needs to be references in std::ref.
std::ref does not make a reference, so in your code sample it doesn't do what you expect. std::ref creates an object that behaves similarly to a reference. It may be useful, for example, when you want to instantiate a functor, and pass a reference-like version of it to a standard library algorithm. Since algorithms take functors by value, you can use std::ref to wrap the functor.
make_tuple(0, a) makes a tuple<int, A>.
make_tuple(0, ref(a)) makes a tuple<int, reference_wrapper<A>>.
You can also say tuple<int, A&> t(0, a); for a tuple you can't make with make_tuple, or use std::tie.
Answering the question in the title (When is the use of std::ref necessary?): Another case where std::ref is useful is when looping over a list of references to objects and modify them:
std::vector<int> v1, v2;
void test() {
for (std::vector<int>& vv :
// Compiles
{ std::ref(v1), std::ref(v2) }
// Compiler rejects this with:
// binding reference of type 'vector<...>' to value of
// type 'const vector<...>' drops 'const' qualifier
// { v1, v2}
) {
vv.push_back(3);
}
}
Without using std::ref in the list, the objects are treated as const and can't be modified (see also https://godbolt.org/z/Ta6YM31KM).