C++ 用于将任意成员函数应用于对象容器的函子
我们正在过渡到C++11,但还有几个月的时间。请随意给出C++11的响应,但我们很好奇在C++98/03中是否有一种非难看的方法来实现这一点C++ 用于将任意成员函数应用于对象容器的函子,c++,boost,functor,boost-bind,C++,Boost,Functor,Boost Bind,我们正在过渡到C++11,但还有几个月的时间。请随意给出C++11的响应,但我们很好奇在C++98/03中是否有一种非难看的方法来实现这一点 一位同事向我走来,代码类似: typedef void(B::*fptr_t)(); void A::my_foreach( uint idx, fptr_t fptr ) { for( iter_type iter = asdf[idx].begin(); iter != asdf[idx].end(); ++iter ) iter-&g
一位同事向我走来,代码类似:
typedef void(B::*fptr_t)();
void A::my_foreach( uint idx, fptr_t fptr ) {
for( iter_type iter = asdf[idx].begin(); iter != asdf[idx].end(); ++iter )
iter->second->*fptr();
}
void A::get( uint idx ) { my_foreach( idx, &B::get ); }
void A::get( uint idx ) { my_foreach( idx, &B::get ); }
。。。询问是否有更好的方法,对此我的回答是:
void A::get( uint idx ) {
std::for_each( asdf[idx].begin()
, asdf[idx].end()
, boost::bind( &B::get, _1 ) );
}
void A::put( uint idx ) {
std::for_each( asdf[idx].begin()
, asdf[idx].end()
, boost::bind( &B::put, _1 ) );
}
。。。但这仍然让我觉得可以做更多的工作来避免代码重复。我想到的一般解决方案是:
应用于我的容器
成员函数,该函数将目标函数作为参数(即,调用方必须提供该函数)boost::bind
包装整个内容,生成一个可以像这样使用的函子:my_binder
将生成一个可以执行相同操作的对象,但由于在上述代码中实际执行了多少函数(操作符[]
,X::begin
,X::end
,将函数ptr应用于容器的每个元素的东西)
在C++11之前是否有其他/更好的方法,或者这些解决方案几乎都是可用的?std::mem\u fn
是步骤4中的活页夹
您没有提到容器看起来是关联的(例如,std::map
)。我建议使用Boost Range来调整范围,以根据映射值进行投影:
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
using namespace boost::adaptors;
template<typename T> struct Container {
template <typename F> void my_foreach(uint idx, F&& f) {
boost::for_each(_data[idx] | map_values, std::forward<F>(f));
}
std::map<int, std::map<int, T> > _data;
};
#include <iostream>
struct B {
B(std::string s) : _s(s) {}
void foo() const { std::cout << "foo(" << _s << ")\n"; }
void bar(int i) const { std::cout << "bar(" << _s << ", " << i << ")\n"; }
private:
std::string _s;
};
#include <functional>
int main() {
Container<B> c;
c._data = { // just some demo data
{ 1, { { 100, {"hundred"} }, { 1000, {"thousand"} }, { 1000000, {"million"} }, } },
{ 2, { { 100, {"hundert"} }, { 1000, {"tausend"} }, { 1000000, {"miljon"} }, } },
{ 3, { { 100, {"cent"} }, { 1000, {"mille"} }, { 1000000, {"million"} }, } },
{ 4, { { 100, {"honderd"} }, { 1000, {"duizen"} }, { 1000000, {"miljoen"} }, } },
};
c.my_foreach(3, std::mem_fn(&B::foo));
c.my_foreach(1, [](B const& b) { b.bar(42); });
}
您可以将boost::bind(&B::get,_1)
替换为std::mem\u-fun(&B::get)
,然后在实际代码中编写一个函数,该函数采用std::mem\u-fun\u-t
,我认为它是向量,但此时的问题更具学术性,因此我省略了确切的容器类型,因为我更感兴趣的是学习一些新的东西,而不是获得特定问题的解决方案(他将其与重复代码一起使用,以避免花费大量时间研究这个问题),您的代码具有iter->second
,因此只有当类型恰好类似于std::pair
时才有意义。您仍然可以使用map\u值
适配器(我想)。如果这一切都无关紧要,那么也许std::mem_fn
才是真正的答案。很好的一点是,我并没有对所使用的容器进行太深入的思考。我将不得不修补mem_fn,更好地了解它的功能。
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
using namespace boost::adaptors;
template<typename T> struct Container {
template <typename F> void my_foreach(uint idx, F&& f) {
boost::for_each(_data[idx] | map_values, std::forward<F>(f));
}
std::map<int, std::map<int, T> > _data;
};
#include <iostream>
struct B {
B(std::string s) : _s(s) {}
void foo() const { std::cout << "foo(" << _s << ")\n"; }
void bar(int i) const { std::cout << "bar(" << _s << ", " << i << ")\n"; }
private:
std::string _s;
};
#include <functional>
int main() {
Container<B> c;
c._data = { // just some demo data
{ 1, { { 100, {"hundred"} }, { 1000, {"thousand"} }, { 1000000, {"million"} }, } },
{ 2, { { 100, {"hundert"} }, { 1000, {"tausend"} }, { 1000000, {"miljon"} }, } },
{ 3, { { 100, {"cent"} }, { 1000, {"mille"} }, { 1000000, {"million"} }, } },
{ 4, { { 100, {"honderd"} }, { 1000, {"duizen"} }, { 1000000, {"miljoen"} }, } },
};
c.my_foreach(3, std::mem_fn(&B::foo));
c.my_foreach(1, [](B const& b) { b.bar(42); });
}
foo(cent)
foo(mille)
foo(million)
bar(hundred, 42)
bar(thousand, 42)
bar(million, 42)