【问题标题】:How to"adapt" functors to use with map/multimap?如何“调整”函子以与地图/多地图一起使用?
【发布时间】:2009-01-27 01:38:21
【问题描述】:

我在使用 std::for_each 和其他具有多重映射的算法时遇到困难,想知道是否有人可以帮助我开发一个可以将适当参数传递给“通用”函数的函子。

我对 map/multimap 的具体问题是它们的迭代器评估为 std::pair 而不是我需要使用的包含值(我的意思是 mapped_type)。所以,我的问题是,有没有办法将正确的值传递给旨在与其中一种包含类型的地图/多地图一起使用的函数?

这是我的示例代码:

// the key type for the multimap
typedef enum { ... } Module;

// my class as the mapped type for the multimap
struct Patch
{
    void Apply(bool enable);
}

// I have some functors designed to work directly with Patch pointers
// because in other places I use set<Patch*> or other containers
struct ApplyOnCondtion: public unary_function<Patch*, void>
{
    void operator() (Patch* patch)
    {
        if(some_condition) patch->Apply(enable_or_not);
    }
}

// somewhere I have a collection of patches attributed to some module
multimap<Module, Patch*> patches;

// the problem is that using for_each with a map or a multimap results in
// a `pair<Module,Patch*>` as argument to the functor, not the Patch* as desired.
for_each(patches.begin(), patches.end(), ApplyOnCondition(...));

我认为也许 bind1st 或 bind2nd 与 mem_fun 结合可以解决这个问题,或者我能想到的另一种方法是创建一个新的仿函数来存储原始仿函数并传递对的正确成员,但我'我没有设法得到任何好的结果。有STL经验的朋友可以给点建议吗?

EDIT 1

好的,在不使用 boost 或额外的临时容器的情况下,我能得到的最好的结果如下:

#include <functional>
#include <utility>
using namespace std;


//////////////////////////////////////////////////////////////////////////
// any functor to be called must be derived from unary_function or
// have defined result_type and argument_type.
// template 'First' should be set to pair::first_type
template<typename First, typename Func>
class passSecond_t: public unary_function<
                        pair<First,typename Func::argument_type>,
                        typename Func::result_type>
{
    Func* func;

public:
    passSecond_t(Func &functor): func(&functor) {}

    result_type operator()(argument_type value)
    {
        return (*func)(value.second);
    }
};

// construction helper, unfortunately 'First' must be explicitly specified
template <typename First, typename Func>
passSecond_t<First, Func> passSecond(Func& functor)
{
    return passSecond_t<First, Func> (functor);
}


// the following is a sample
#include <map>
#include <algorithm>
#include <iostream>

struct SampleClass 
{
    void execute(char* text)
    {
        cout << "this: " << this << ", text: " << text << endl;
    }
};

struct SampleFunctor: public unary_function<SampleClass*,void>
{
    char* text;
    SampleFunctor(char* text_): text(text_) {}

    result_type operator() (argument_type argu)
    {
        argu->execute(text);
    }
};

void main()
{
    map<int,SampleClass*> mymap;
    SampleClass s1, s2;
    mymap[0] = &s1;
    mymap[1] = &s2;

    SampleFunctor myfunctor("my text");

    for_each(mymap.begin(), mymap.end(), passSecond<int>(myfunctor));
}

【问题讨论】:

    标签: c++ stl map functor multimap


    【解决方案1】:

    一开始我有一个提升解决方案:

    for_each(patches.begin(), patches.end(), 
             boost::bind(ApplyOnCondition(...),
                         boost::bind(&map_type::value_type::second, _1)));
    

    这会获取该对的 ::second 成员,并将其推送到 ApplyOnCondition 的 operator()。 map_type 是地图的类型(当然是multimap&lt;Module, Patch*&gt;)。

    【讨论】:

      【解决方案2】:

      您可以使用std::transform获取所有值:

      std::multimap<Module, Patch *> patches;
      
      std::vector<Patch *> values(patches.size());
      std::transform(patches.begin(), patches.end(), values.begin(),
          std::select2nd<std::multimap<Module, Patch *>::value_type>());
      

      然后在那个向量上std::for_each

      std::for_each(values.begin(), values.end(), ApplyOnCondition(...));
      

      【讨论】:

        【解决方案3】:

        这是一个更类似于使用函数式语言的解决方案:

          /**
           * Applies a function to the values in a map, producing a map with the same
           * keys but containing the values produced by the function.
           * In Haskell, the type of this function would be something like
           * mapply :: (a -> b) -> Map c a -> Map c b
           */
          template<typename Function, typename Key, typename InValue, typename OutValue>
          static std::map<Key, OutValue> mapply(Function function, const std::map<Key, InValue>& inMap) {
            typedef typename std::map<Key, InValue>::const_iterator InIterator;
            const InIterator end(inMap.end());
            std::map<Key, OutValue> outMap;
            for (InIterator i(inMap.begin()); i != end; ++i) {
              outMap.insert(std::make_pair(i->first, function(i->second)));
            }
            return outMap;
          }
        

        此代码符合 C++98。在 C++11 中,它可以被简化。

        另请注意,该函数按值返回地图。如果您没有迹象表明这是您的性能瓶颈(过早的优化是万恶之源),那没关系,但是如果您有一个巨大的地图并且不相信您的编译器会进行优化,那么您可能宁愿拥有“mapply”函数通过引用获取 out 参数的解决方案:用键值对填充的映射。

        【讨论】:

          猜你喜欢
          • 2015-06-29
          • 1970-01-01
          • 2017-11-05
          • 2017-05-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多