У вас есть три проблемы:
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);
}
}