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

时间:2011-10-13 19:36:27

标签: c++ boost boost-phoenix

这是我在这里发表的第一篇文章,如果我不尊重“方式和风俗”,那就很好了:)

我是使用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 个答案:

答案 0 :(得分:1)

你有三个问题:

  1. boost::phoenix::function<>是懒惰的,因此必须对其进行两次评估才能获得实际结果。
  2. rouletteWheelSelector::operator()必须为const才能由boost::phoenix::function<>使用。
  3. sel按值捕获stations,从而将迭代器返回到已销毁的集合中;使用boost::phoenix::cref通过const-reference捕获stations
  4. 此代码使用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在他现在删除的答案中正确指出的那样,您必须在result<>内使用嵌套的rouletteWheelSelector模板,而不是{{1 }}:

    result_type

    然而,所有这一切,为什么你在这里使用struct rouletteWheelSelector { template<typename> struct result { typedef BTSSet::iterator type; }; BTSSet::iterator operator ()(BTSSet const& stations) const { return stations.begin(); } }; ?对于您的使用,boost::phoenix::function<>可以在没有它的情况下更容易(并且有效)地实施:

    Greedy<>