Как передать функцию в параметре с 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:: Итератор.
С моей декларацией функтора все в порядке? Как я могу заставить компилятор определить правильный тип возвращаемого значения sel?
Спасибо!
1 ответ
У вас есть три вопроса:
boost::phoenix::function<>
ленивый, поэтому он должен быть оценен дважды, чтобы получить реальный результат.rouletteWheelSelector::operator()
должен быть постоянным для того, чтобы быть использованнымboost::phoenix::function<>
,sel
захватываетstations
по значению и, следовательно, возвращая итератор в уничтоженное множество; использование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 в своем удаленном ответе, вы должны использовать вложенный result<>
шаблон внутри rouletteWheelSelector
скорее, чем 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<>
может быть легко (и эффективно) реализовано без него:
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);
}
}