C++ 用于将任意成员函数应用于对象容器的函子

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

我们正在过渡到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->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 ) );
}
。。。但这仍然让我觉得可以做更多的工作来避免代码重复。我想到的一般解决方案是:

  • 重新分解代码,使相关类的责任更小,并将容器包装在decorator/proxy对象中,以提供一些所需的功能
  • 泛型
    应用于我的容器
    成员函数,该函数将目标函数作为参数(即,调用方必须提供该函数)
  • 生成两个私有成员函数:一个是(2)中提到的函数,另一个是返回一个functor来调用它,然后在构造函数中初始化公共functor对象
  • 使用
    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)