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

时间:2017-09-29 19:47:15

标签: 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->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 ) );
}

...但仍然让我觉得可以采取更多措施来避免代码重复。我遇到的一般解决方案是:

  1. 对代码进行重新分解,以使所涉及的类具有较少的职责,并将容器包装在提供一些所需功能的装饰器/代理对象中。
  2. 将预期函数作为参数的通用apply to my container成员函数(即调用者必须提供函数)
  3. 创建两个私有成员函数:(2)中提到的函数和一个返回函数来调用它的函数,然后是在构造函数中初始化的公共函子对象。
  4. 使用boost::bind包装整个内容,制作一个可以像这样使用的仿函数:
  5. functor_t get = my_binder( &B::get );
    functor_t put = my_binder( &B::put );
    

    ...其中my_binder会生成一个可以执行相同操作的对象,但由于上述代码中实际执行了多少函数,因此很快变得丑陋(operator[],{{1 }},X::beginX::end)。

    在C ++ 11之前是否有其他/更好的方法,或者那些解决方案几乎可用?

1 个答案:

答案 0 :(得分:1)

std::mem_fn是步骤4中的活页夹。

您并未完全提及您的容器看起来是关联的(例如std::map)。我建议使用Boost Range来调整范围以投影到映射值:

<强> Live On Coliru

#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)