如何使用Boost::Phoenix传递函数参数

How to pass a function in parameter with Boost::Phoenix?

本文关键字:传递函数 参数 Phoenix Boost 何使用      更新时间:2023-10-16

这是我在这里的第一个帖子,如果我不尊重"方式和习俗",请原谅我:)

我是新使用Boost::Phoenix,我想传递一个函数给方法定义如下:

template <typename Selector>
Result Greedy ( 
    const t_Capacity& capacity,
    BTSSet stations,                
    BTSSet startSet)               
{
  //...
  function <Selector> sel;
  while ( !stations.empty() ) { 
    BTSSet::iterator currentStation = sel(stations);
    // ...
    }
// ...
}

我的选择器函数是:

struct rouletteWheelSelector {
  typedef BTSSet::iterator result_type;
  BTSSet::iterator operator () ( const BTSSet& stations ) { 
    // ...
  }
};

但是我的编译器说没有办法从from 'typename detail::expression::function_eval<rouletteWheelSelector, set<BTS *, BTS_Cmp, allocator<BTS *> > >::type const'转换为BTSSet::Iterator。

我的函子声明没问题吗?如何强制编译器推断出sel的正确返回类型?

有三个问题:

  1. boost::phoenix::function<>是惰性的,因此必须计算两次才能得到实际的结果。
  2. rouletteWheelSelector::operator()必须为const才能被boost::phoenix::function<>使用。
  3. sel按值捕获stations,因此返回一个销毁集合的迭代器;
  4. 使用boost::phoenix::cref捕获stations

这段代码在vc++ 2010 SP1和Boost 1.47.0下编译和运行得很干净:

#include <memory>
#include <set>
#include <boost/phoenix.hpp>
struct BTS
{
    explicit BTS(int const val_) : val(val_) { }
    int val;
};
struct BTS_Cmp
{
    typedef bool result_type;
    bool operator ()(BTS const* const a, BTS const* const b) const
    {
        if (a && b)
            return a->val < b->val;
        if (!a && !b)
            return false;
        return !a;
    }
};
typedef std::set<BTS*, BTS_Cmp> BTSSet;
struct rouletteWheelSelector
{
    typedef BTSSet::iterator result_type;
    BTSSet::iterator operator ()(BTSSet const& stations) const
    {
        return stations.begin();
    }
};
template<typename Selector>
void Greedy(BTSSet stations)
{
    namespace phx = boost::phoenix;
    phx::function<Selector> sel;
    while (!stations.empty())
    {
        BTSSet::iterator currentStation = sel(phx::cref(stations))();
        std::auto_ptr<BTS> deleter(*currentStation);
        stations.erase(currentStation);
    }
}
int main()
{
    BTSSet stations;
    stations.insert(new BTS(1));
    stations.insert(new BTS(2));
    stations.insert(new BTS(3));
    stations.insert(new BTS(4));
    stations.insert(new BTS(5));
    Greedy<rouletteWheelSelector>(stations);
}

如果您使用的是Phoenix v2而不是Phoenix v3,正如@jpalecek在他现在已删除的回答中正确指出的那样,您必须在rouletteWheelSelector而不是result_type中使用嵌套的result<>模板:

struct rouletteWheelSelector
{
    template<typename>
    struct result
    {
        typedef BTSSet::iterator type;
    };
    BTSSet::iterator operator ()(BTSSet const& stations) const
    {
        return stations.begin();
    }
};

然而,说了这么多,为什么你在这里使用boost::phoenix::function<> ?对于您的使用,没有它,Greedy<>可以更容易(和有效)地实现:

template<typename Selector>
void Greedy(BTSSet stations)
{
    Selector sel;
    while (!stations.empty())
    {
        BTSSet::iterator currentStation = sel(stations);
        std::auto_ptr<BTS> deleter(*currentStation);
        stations.erase(currentStation);
    }
}