Reputation:
#include <vector>
#include <functional>
#include <algorithm>
using namespace std;
struct Foo
{
int i;
double d;
Foo(int i, double d) :
i(i),
d(d)
{}
int getI() const { return i; }
};
int main()
{
vector<Foo> v;
v.push_back(Foo(1, 2.0));
v.push_back(Foo(5, 3.0));
vector<int> is;
transform(v.begin(), v.end(), back_inserter(is), mem_fun_ref(&Foo::getI));
return 0;
}
Is there a cleaner way to access a member variable then then using a member function like I have above? I know how to do it using tr1::bind, but I need to have C++03 compliant code without boost.
Upvotes: 4
Views: 781
Reputation: 264441
Like std::pair you could write access-or objects.
#include <vector>
#include <algorithm>
struct Foo
{
int i;
double d;
};
struct GetI { int operator()(Foo const& o) const { return o.i;}};
struct GetD { double operator()(Foo const& o) const { return o.d;}};
int main()
{
std::vector<Foo> v;
std::vector<int> t;
std::transform(v.begin(), v.end(), std::back_inserter(t),GetI() );
}
Note: You should look at std::pair<T1,T2>
And its accessors: std::select1st<T1> and std::select2nd<T2>
Upvotes: 3
Reputation: 41509
It's absolutely unclean to need an accessor function in order to do that. But that's the current C++.
You could try using boost::bind
, which does the trick quite easily, or iterate the vector explicitly, using a for( vector<int>::const_iterator it = v.begin(); .....)
loop. I find the latter often resulting in clearer code when the creation of the functor becomes too much a hassle.
Or, shunning boost, create your own member-accessor shim function.
template< typename T, typename m > struct accessor_t {
typedef m (T::*memberptr);
memberptr acc_;
accessor_t( memberptr acc ): acc_(acc){}
// accessor_t( m (T::*acc) ): acc_(acc){}
// m (T::*acc_);
const m& operator()( const T& t ) const { return (t.*acc_); }
m& operator()( T& t ) const { return (t.*acc_); }
};
template< typename T, typename m > accessor_t<T,m> accessor( m T::*acc ) {
return accessor_t<T,m>(acc);
}
...
transform( v.begin(), v.end(), back_inserter(is), accessor( &C::i ) );
Upvotes: 8
Reputation: 99585
The most clear way for me is boost::bind
:
#include <boost/bind.hpp>
...
transform(v.begin(), v.end(), back_inserter(is), bind( &Foo::i, _1 ) );
Surely you could create your own member access function, but I believe it will make your code less readable. boost::bind is widely known library, so using it will make your code pretty readable and no need to read your helper functions (which could contain bugs occasionally)
The second way I prefer is just to use for-loop (in this particular case):
for ( vector<Foo>::const_iterator it = v.begin(), it != v.end(); ++it )
is.push_back( it->i );
May be it is not fashionable to use such simple loops, but they are very clear.
Upvotes: 2