Question

I have a class with an accessor member function that I want to call and apply the result to a functor using std::for_each. I have a working version below that uses a for loop and for_each, but the for_each version is cryptic and cumbersome. Is there a way I can make the for_each version more concise, considering I have access to boost, but not C++11?

#if 0
   // for loop version:
   for(value_vector_type::iterator it = values.begin(); it!=values.end(); it++){
     avg(it->getValue());  // I want to put this in a for_each loop
   }
#else
  //  bind version:
  std::for_each(values.begin(), values.end(), // iterate over all values
    boost::bind(
      boost::mem_fn(&average_type::operator()), // attach the averaging functor to the output of the getvalue call
      &avg, 
      boost::bind(
        boost::mem_fn(&value_wrapper_type::getValue), // bind the getValue call to each element in values
        _1
      )
    )
  );
#endif    

Here is the full working implementation:

#include <vector>
#include <algorithm>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/bind/mem_fn.hpp>

// A value wrapper
template<typename T>
struct Value {
  Value(){}
  Value(const T& value, bool valid = true):m_value(value),m_valid(valid){}

  T getValue(){ return m_value; }
  bool getValid(){ return m_valid; }
  void setValue(const T& value){ m_value = value; }
  void setValid(const T& valid){ m_valid = valid; }

private:
  T m_value;
  bool m_valid;   
};

// Class that calculates the average piecewise
template<typename T>
struct Average {
private:
    T m_numPoints;
    T m_ChannelSum;

public:

    Average() : m_numPoints(0), m_ChannelSum(0.0){}

    void operator()(T value){
        m_numPoints++;
        m_ChannelSum+=value;
    }

    double getAverage(){ return m_ChannelSum/m_numPoints; }
    T getCount(){ return m_numPoints; }
    T getSum(){ return m_ChannelSum; }
};

// Run the average computation on several values
int main(int argc, char** argv){
  typedef int value_type;
  typedef Value<value_type> value_wrapper_type;
  typedef std::vector<value_wrapper_type> value_vector_type;
  value_vector_type values;
  values.push_back(value_wrapper_type(5));
  values.push_back(value_wrapper_type(7));
  values.push_back(value_wrapper_type(3));
  values.push_back(value_wrapper_type(1));
  values.push_back(value_wrapper_type(2));

  typedef Average<value_type> average_type;
  average_type avg;

#if 0
   // for loop version:
   for(value_vector_type::iterator it = values.begin(); it!=values.end(); it++){
     avg(it->getValue());  // I want to put this in a for_each loop
   }
#else
  //  bind version:
  std::for_each(values.begin(), values.end(), // iterate over all values
    boost::bind(
      boost::mem_fn(&average_type::operator()), // attach the averaging functor to the output of the getvalue call
      &avg, 
      boost::bind(
        boost::mem_fn(&value_wrapper_type::getValue), // bind the getValue call to each element in values
        _1
      )
    )
  );
#endif    
  std::cout << "Average: " << avg.getAverage() << " Count: " << avg.getCount() << " Sum: " << avg.getSum() << std::endl;
}

note: my original question was how to construct a for_each at all, but I've found that solution and a whole new question did not make much sense.

Thanks, all help is really appreciated!

Was it helpful?

Solution 4

Credit goes to Mathias Gaunard on the boost.users mailing list for pointing me towards this solution:

  std::for_each(values.begin(), values.end(),
    boost::bind(boost::ref(avg), boost::bind(&value_wrapper_type::getValue, _1))
  );

Wrapping avg with boost::ref is required because otherwise a copy of avg is filled out with the results of getValue(), rather than avg itself.

Here is the full compiled and tested solution:

#include <stdexcept>
#include <vector>
#include <algorithm>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/bind/mem_fn.hpp>

// A value wrapper
template<typename T>
struct Value {
  Value(){}
  Value(const T& value, bool valid = true):m_value(value),m_valid(valid){}

  T getValue(){ return m_value; }
  bool getValid(){ return m_valid; }
  void setValue(const T& value){ m_value = value; }
  void setValid(const T& valid){ m_valid = valid; }

private:
  T m_value;
  bool m_valid;   
};

// Class that calculates the average piecewise
template<typename T>
struct Average {
private:
    T m_numPoints;
    T m_ChannelSum;

public:
  typedef void result_type;

    Average() : m_numPoints(0), m_ChannelSum(0.0){}

    result_type operator()(T value){
        m_numPoints++;
        m_ChannelSum+=value;
    }

    double getAverage(){ 
    if (m_ChannelSum==0) {
      throw std::logic_error("Cannot get average of zero values");
    }

    return m_ChannelSum/m_numPoints; 
  }
    T getCount(){ return m_numPoints; }
    T getSum(){ return m_ChannelSum; }
};

// Run the average computation on several values
int main(int argc, char** argv){
  typedef int value_type;
  typedef Value<value_type> value_wrapper_type;
  typedef std::vector<value_wrapper_type> value_vector_type;
  value_vector_type values;
  values.push_back(value_wrapper_type(5));
  values.push_back(value_wrapper_type(7));
  values.push_back(value_wrapper_type(3));
  values.push_back(value_wrapper_type(1)); 
  values.push_back(value_wrapper_type(2));

  typedef Average<value_type> average_type;
  average_type avg;

#if 0
  // for loop version:
  for(value_vector_type::iterator it = values.begin(); it!=values.end(); it++){
   avg(it->getValue());  // I want to put this in a for_each loop
  }
#else
  //  bind version:
  std::for_each(values.begin(), values.end(),
    boost::bind(boost::ref(avg), boost::bind(&value_wrapper_type::getValue, _1))
  );
#endif    
  std::cout << "Average: " << avg.getAverage() << " Count: " << avg.getCount() << " Sum: " << avg.getSum() << std::endl;
}

OTHER TIPS

If you don't have C++11 but Boost you could try a bind() expression (which would also work with C++2011 as bind() is part of C++2011):

std::for_each(a.begin(), a.end(), bind(&avg<value_type>, bind(&Value<value_type>::getValue, _1)));

if you are using c++11 then you can try

for(auto& a: values)
    avg(a->getValue());

or

std::for_each(a.begin(), a.end(), [](whatever_type& wt){
    avg(wt->getValue());
});

If you are not, then I think that toy have as good as your going to get although formatting wont hurt.

for(value_vector_type::iterator it = values.begin(); 
    it!=values.end(); 
    ++it)
{
    avg(it.getValue());  // I want to put this in a for_each loop
}

Trying to be too clever with function object and the like can often have the inverse effect of obscuring your code.

One way to make it look neater is to use Boost.Phoenix. You can shorten down to this:

std::for_each(values.begin(), values.end(), lazy(avg)(arg1.getValue()));

Heres how to do that. First thing you need to do is make the avg function object lazy. The simplest way to that is in-place with a function, defined like this:

template<class Function>
function<Function> lazy(Function x)
{
    return function<Function>(x);
}

Next thing you need to do is write a function object for getValue, that can be lazy, like this:

struct get_value_impl
{
    // result_of protocol:
    template <typename Sig>
    struct result;

    template <typename This, typename T>
    struct result<This(Value<T>&)>
    {
        // The result will be T
        typedef typename T type;
    };

    template <typename V>
    typename result<get_value_impl(V &)>::type
    operator()(V & value) const
    {
        return value.getValue();
    }
};

Thirdly, we extend the phoenix actors, using our get_value_impl class, so it will have a getValue method, like this:

template <typename Expr>
struct value_actor
    : actor<Expr>
{
    typedef actor<Expr> base_type;
    typedef value_actor<Expr> that_type;

    value_actor( base_type const& base )
        : base_type( base ) {}

    typename expression::function<get_value_impl, that_type>::type const
    getValue() const
    {
        function<get_value_impl> const f = get_value_impl();
        return f(*this);
    }
};

Finally, we put it all together by defining the argument and passing it into the for_each algorithm:

expression::terminal<phoenix::argument<1>, value_actor>  arg1;
std::for_each(values.begin(), values.end(), lazy(avg)(arg1.getValue()));

If you can use boost, but not C++11 features, then I would consider using the BOOST_FOREACH macro

Yes, it's a macro, but as macros go it's well behaved

It's also reads quite nicely and is hard to get wrong

BOOST_FOREACH(const Value& rValue, values)
{
    avg(rValue.getValue());
}

C++11 range based for loops will replace it

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top