【问题标题】:How to pass a function in parameter with Boost::Phoenix?如何使用 Boost::Phoenix 在参数中传递函数?
【发布时间】:2011-10-13 19:36:27
【问题描述】:

这是我在这里的第一篇文章,如果我不尊重“方式和习俗”,请善待:)

我是使用 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&lt;rouletteWheelSelector, set&lt;BTS *, BTS_Cmp, allocator&lt;BTS *&gt; &gt; &gt;::type const' 转换为 BTSSet::Iterator。

我的仿函数声明好吗?如何强制编译器推断 sel 的正确返回类型?

谢谢!

【问题讨论】:

  • 你试过让rouletteWheelSelector::operator() const 吗?

标签: c++ boost boost-phoenix


【解决方案1】:

你有三个问题:

  1. boost::phoenix::function&lt;&gt; 是惰性的,因此必须计算两次才能得到实际结果。
  2. rouletteWheelSelector::operator() 必须是 const 才能被 boost::phoenix::function&lt;&gt; 使用。
  3. sel 按值捕获 stations,因此将迭代器返回到已销毁的集合中;使用 boost::phoenix::cref 通过 const-reference 捕获 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&lt;&gt; 模板而不是 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&lt;&gt;?对于您的使用,Greedy&lt;&gt; 可以在没有它的情况下更容易(并且更有效地)实现:

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);
    }
}

【讨论】:

  • 哇!谢谢 !对于初学者来说,您的答案是真正的金矿!我会尽我所能理解和纠正一切:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-25
  • 1970-01-01
  • 1970-01-01
  • 2021-04-30
  • 1970-01-01
相关资源
最近更新 更多