我有一个带有访问者成员函数的类,我想调用它并使用std :: for_each将结果应用于仿函数。我在下面有一个使用for循环和for_each的工作版本,但是for_each版本很神秘且很麻烦。有没有办法让for_each版本更简洁,考虑到我有权访问boost,而不是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
以下是完整的工作实施:
#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;
}
注意:我原来的问题是如何构建for_each,但我发现解决方案和一个全新的问题没有多大意义。
谢谢,非常感谢所有帮助!
答案 0 :(得分:2)
如果您使用的是c ++ 11,那么您可以尝试
for(auto& a: values)
avg(a->getValue());
或
std::for_each(a.begin(), a.end(), [](whatever_type& wt){
avg(wt->getValue());
});
如果你不是,那么我认为虽然格式不会受到影响,但玩具的效果会与你的玩具一样好。
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
}
尝试使用函数对象等过于聪明通常会产生模糊代码的反向效果。
答案 1 :(得分:2)
如果您没有C ++ 11但是Boost可以尝试bind()
表达式(这也适用于C ++ 2011,因为bind()
是C ++ 2011的一部分):
std::for_each(a.begin(), a.end(), bind(&avg<value_type>, bind(&Value<value_type>::getValue, _1)));
答案 2 :(得分:1)
让它看起来更整洁的一种方法是使用Boost.Phoenix。你可以缩短到这个:
std::for_each(values.begin(), values.end(), lazy(avg)(arg1.getValue()));
继承人如何做到这一点。您需要做的第一件事是使avg
函数对象变得懒惰。最简单的方法就是使用一个函数,就像这样定义:
template<class Function>
function<Function> lazy(Function x)
{
return function<Function>(x);
}
接下来你需要做的是为getValue编写一个函数对象,它可以是懒惰的,如下所示:
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();
}
};
第三,我们使用我们的get_value_impl
类来扩展凤凰演员,所以它将有一个getValue
方法,如下所示:
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);
}
};
最后,我们通过定义参数并将其传递给for_each算法来将它们全部放在一起:
expression::terminal<phoenix::argument<1>, value_actor> arg1;
std::for_each(values.begin(), values.end(), lazy(avg)(arg1.getValue()));
答案 3 :(得分:0)
关于boost.users邮件列表上的Mathias Gaunard,我指的是这个解决方案:
std::for_each(values.begin(), values.end(),
boost::bind(boost::ref(avg), boost::bind(&value_wrapper_type::getValue, _1))
);
需要使用avg
包裹boost::ref
,否则avg
的副本会填写getValue()
的结果,而不是avg
本身。< / p>
以下是完整的经过编译和测试的解决方案:
#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;
}
答案 4 :(得分:0)
如果您可以使用boost而不是C ++ 11功能,那么我会考虑使用the BOOST_FOREACH macro
是的,它是一个宏,但是随着宏的发展,它的表现很好
它也读得很好而且很难出错
BOOST_FOREACH(const Value& rValue, values)
{
avg(rValue.getValue());
}
基于C ++ 11范围的for循环将取代它