开发者

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

开发者 https://www.devze.com 2023-04-13 09:15 出处:网络
It\'s my first post here so plese be kind if I 开发者_开发问答don\'t respect the \"ways and customs\" :)

It's my first post here so plese be kind if I 开发者_开发问答don't respect the "ways and customs" :)

I'm new using Boost::Phoenix and I want to pass a function to a methods defined like :

template <typename Selector>
Result Greedy ( 
    const t_Capacity& capacity,
    BTSSet stations,                
    BTSSet startSet)               
{
  //...

  function <Selector> sel;
  while ( !stations.empty() ) { 
    BTSSet::iterator currentStation = sel(stations);

    // ...
    }
// ...
}

My selector function is :

struct rouletteWheelSelector {
  typedef BTSSet::iterator result_type;

  BTSSet::iterator operator () ( const BTSSet& stations ) { 
    // ...
  }
};

But my compiler says there's no way to convert from from 'typename detail::expression::function_eval<rouletteWheelSelector, set<BTS *, BTS_Cmp, allocator<BTS *> > >::type const' to BTSSet::Iterator.

Is my functor declaration ok ? How can I force the compiler to deduce the right return type of sel ?

Thank you !


You have three issues:

  1. boost::phoenix::function<> is lazy, so it must be evaluated twice in order to get an actual result.
  2. rouletteWheelSelector::operator() must be const in order to be used by boost::phoenix::function<>.
  3. sel is capturing stations by value, and consequently returning an iterator into a destroyed set; use boost::phoenix::cref to capture stations by const-reference.

This code compiles and runs cleanly for me with VC++ 2010 SP1 and 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);
}

If you're using Phoenix v2 rather than Phoenix v3, as @jpalecek correctly noted in his now-deleted answer, you must use a nested result<> template inside of rouletteWheelSelector rather than result_type:

struct rouletteWheelSelector
{
    template<typename>
    struct result
    {
        typedef BTSSet::iterator type;
    };

    BTSSet::iterator operator ()(BTSSet const& stations) const
    {
        return stations.begin();
    }
};

However, all that said, why are you using boost::phoenix::function<> at all here? For your usage, Greedy<> could more easily (and efficiently) be implemented without it:

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

精彩评论

暂无评论...
验证码 换一张
取 消