Оценивая результат boost :: phoenix :: insert

У меня возникают трудности при попытке оценить результат boost::phoenix::insert который вставляет элементы в карту. Похож на обычный std::map::insert объект субъекта, возвращенный boost::phoenix::insert также возвращает std::pair<Iterator where, bool result>, Я заинтересован во втором элементе этой пары, чтобы проверить, была ли вставка успешной. Пример сильно урезанного кода, иллюстрирующий проблему, выглядит следующим образом:

#include <iostream>
#include <boost/phoenix/fusion.hpp>
#include <boost/phoenix/phoenix.hpp>
#include <boost/fusion/include/all.hpp>
#include <boost/fusion/include/std_pair.hpp>

int main(int, char*[])
{
namespace phx = boost::phoenix;
using phx::arg_names::arg1;
using phx::arg_names::arg2;

std::map<int, int> map;
std::pair<int, int> value(1, 2);

if (phx::at_c<1>(phx::insert(arg1, arg2))(map, value)) // <- Error here
std::cout << "Success" << std::endl;
else
std::cout << "Fail" << std::endl;

return 0;
}

Я получаю следующую ошибку, используя MSVC2012 и повысить 1,53:

error C2440: 'return' : cannot convert from 'const bool' to 'bool &'
<some-path>\include\boost\proto\transform\call.hpp:258

clang3.2 сообщает об ошибке:

Compilation finished with errors:
In file included from source.cpp:2:
In file included from /usr/local/include/boost/phoenix/fusion.hpp:14:
In file included from /usr/local/include/boost/phoenix/fusion/at.hpp:14:
In file included from /usr/local/include/boost/phoenix/core/expression.hpp:10:
In file included from /usr/local/include/boost/phoenix/core/as_actor.hpp:10:
In file included from /usr/local/include/boost/phoenix/core/actor.hpp:17:
In file included from /usr/local/include/boost/phoenix/core/domain.hpp:12:
In file included from /usr/local/include/boost/proto/matches.hpp:43:
In file included from /usr/local/include/boost/proto/transform/when.hpp:22:
/usr/local/include/boost/proto/transform/call.hpp:255:24: error: binding of reference to type 'bool' to a value of type 'const bool' drops qualifiers
return typename detail::poly_function_traits<Fun, Fun(a0, a1)>::function_type()(
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/boost/phoenix/core/meta_grammar.hpp:74:24: note: in instantiation of member function 'boost::proto::call<boost::proto::functional::at (boost::phoenix::evaluator (*)(boost::proto::_child_c<1>), boost::proto::_value (*)(boost::proto::_child_c<0>))>::impl2<const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::at_c, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<mpl_::int_<1> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::stl::insert>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<2> >, 0> > >, 3> > >, 2> > &, boost::phoenix::vector3<const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::at_c, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<mpl_::int_<1> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::stl::insert>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<2> >, 0> > >, 3> > >, 2> > *, std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > > &, std::pair<int, int> &> &, const boost::phoenix::default_actions &, false>::operator()' requested here
return what()(e, phoenix::env(s), actions(s));
^
/usr/local/include/boost/phoenix/core/meta_grammar.hpp:34:9: note: in instantiation of member function 'boost::phoenix::evaluator::impl<const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::at_c, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<mpl_::int_<1> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::stl::insert>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<2> >, 0> > >, 3> > >, 2> > &, const boost::phoenix::vector2<boost::phoenix::vector3<const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::at_c, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<mpl_::int_<1> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::stl::insert>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<2> >, 0> > >, 3> > >, 2> > *, std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > > &, std::pair<int, int> &> &, const boost::phoenix::default_actions &> &, boost::proto::envns_::empty_env>::operator()' requested here
BOOST_PROTO_TRANSFORM(evaluator)
^
/usr/local/include/boost/proto/transform/impl.hpp:228:9: note: expanded from macro 'BOOST_PROTO_TRANSFORM'
BOOST_PROTO_TRANSFORM_(PrimitiveTransform, void)                                                        \
^
/usr/local/include/boost/proto/transform/impl.hpp:213:16: note: expanded from macro 'BOOST_PROTO_TRANSFORM_'
return boost::proto::detail::apply_transform<transform_type(Expr const &, State const &)>()(e, s, d);   \
^
/usr/local/include/boost/phoenix/core/meta_grammar.hpp:139:16: note: in instantiation of function template specialization 'boost::phoenix::evaluator::operator()<const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::at_c, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<mpl_::int_<1> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::stl::insert>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<2> >, 0> > >, 3> > >, 2> > &, const boost::phoenix::vector2<boost::phoenix::vector3<const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::at_c, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<mpl_::int_<1> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::stl::insert>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<2> >, 0> > >, 3> > >, 2> > *, std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > > &, std::pair<int, int> &> &, const boost::phoenix::default_actions &> &>' requested here
return e(expr, ctx);
^
/usr/local/include/boost/phoenix/core/detail/preprocessed/actor_operator_10.hpp:31:385: note: in instantiation of function template specialization 'boost::phoenix::eval<boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::at_c, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<mpl_::int_<1> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::stl::insert>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<2> >, 0> > >, 3> > >, 2> >, boost::phoenix::vector2<boost::phoenix::vector3<const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::at_c, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<mpl_::int_<1> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::stl::insert>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<2> >, 0> > >, 3> > >, 2> > *, std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > > &, std::pair<int, int> &> &, const boost::phoenix::default_actions &> >' requested here
template <typename This, typename A0 , typename A1> struct result<This(A0 & , A1 &)> : result_of::actor<proto_base_expr, A0 & , A1 &> {}; template <typename A0 , typename A1> typename result_of::actor<proto_base_expr, A0 & , A1 &>::type operator()(A0 & a0 , A1 & a1) const { typedef vector3< const actor<Expr> *, A0 & , A1 & > env_type; env_type env = {this, a0 , a1}; return phoenix::eval(*this, phoenix::context(env, default_actions())); } template <typename A0 , typename A1> typename result_of::actor<proto_base_expr, A0 & , A1 &>::type operator()(A0 & a0 , A1 & a1) { typedef vector3< const actor<Expr> *, A0 & , A1 & > env_type; env_type env = {this, a0 , a1}; return phoenix::eval(*this, phoenix::context(env, default_actions())); } template <typename This, typename A0 , typename A1> struct result<This(A0 & , A1 const&)> : result_of::actor<proto_base_expr, A0 & , A1 const&> {}; template <typename A0 , typename A1> typename result_of::actor<proto_base_expr, A0 & , A1 const&>::type operator()(A0 & a0 , A1 const& a1) const { typedef vector3< const actor<Expr> *, A0 & , A1 const& > env_type; env_type env = {this, a0 , a1}; return phoenix::eval(*this, phoenix::context(env, default_actions())); } template <typename A0 , typename A1> typename result_of::actor<proto_base_expr, A0 & , A1 const&>::type operator()(A0 & a0 , A1 const& a1) { typedef vector3< const actor<Expr> *, A0 & , A1 const& > env_type; env_type env = {this, a0 , a1}; return phoenix::eval(*this, phoenix::context(env, default_actions())); } template <typename This, typename A0 , typename A1> struct result<This(A0 const& , A1 &)> : result_of::actor<proto_base_expr, A0 const& , A1 &> {}; template <typename A0 , typename A1> typename result_of::actor<proto_base_expr, A0 const& , A1 &>::type operator()(A0 const& a0 , A1 & a1) const { typedef vector3< const actor<Expr> *, A0 const& , A1 & > env_type; env_type env = {this, a0 , a1}; return phoenix::eval(*this, phoenix::context(env, default_actions())); } template <typename A0 , typename A1> typename result_of::actor<proto_base_expr, A0 const& , A1 &>::type operator()(A0 const& a0 , A1 & a1) { typedef vector3< const actor<Expr> *, A0 const& , A1 & > env_type; env_type env = {this, a0 , a1}; return phoenix::eval(*this, phoenix::context(env, default_actions())); } template <typename This, typename A0 , typename A1> struct result<This(A0 const& , A1 const&)> : result_of::actor<proto_base_expr, A0 const& , A1 const&> {}; template <typename A0 , typename A1> typename result_of::actor<proto_base_expr, A0 const& , A1 const&>::type operator()(A0 const& a0 , A1 const& a1) const { typedef vector3< const actor<Expr> *, A0 const& , A1 const& > env_type; env_type env = {this, a0 , a1}; return phoenix::eval(*this, phoenix::context(env, default_actions())); } template <typename A0 , typename A1> typename result_of::actor<proto_base_expr, A0 const& , A1 const&>::type operator()(A0 const& a0 , A1 const& a1) { typedef vector3< const actor<Expr> *, A0 const& , A1 const& > env_type; env_type env = {this, a0 , a1}; return phoenix::eval(*this, phoenix::context(env, default_actions())); }
^
source.cpp:16:44: note: in instantiation of function template specialization 'boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::at_c, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<mpl_::int_<1> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::stl::insert>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<2> >, 0> > >, 3> > >, 2> >::operator()<std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >, std::pair<int, int> >' requested here
if (phx::at_c<1>(phx::insert(arg1, arg2))(map, value))
^
1 error generated.

У меня заканчиваются идеи, как правильно оценить результат вставки. Любая помощь будет оценена.

Редактировать:
Более широкий контекст моего вопроса заключается в том, что я пытаюсь проанализировать перечисление, подобное C ++, используя boost :: spirit :: qi. Любые примеры, которые я нашел, которые пытаются достичь того же, не проверяют дубликаты членов перечисления. Вот фрагмент кода с двумя соответствующими правилами:

  enumerationMember = identifier[at_c<0>(_val) = _1] >
// If there is an explicit value defined use it.
((lit('=') > int_[at_c<1>(_val) = _1]) |
// Otherwise use the value of argument _r1 instead.
eps[at_c<1>(_val) = _r1]);
enumeration = lit("enum") > typeName[at_c<0>(_val) = _1] > lit(':') >
enumerationType[at_c<1>(_val) = _1] > braceOpen >
// Initialize _a with 0.
eps[_a = 0] >
// Zero or one comma separated list of members.
-(enumerationMember(_a)[//_pass = boost::phoenix::at_c<1>( <- I'm looking for something like this..
insert(at_c<2>(_val), _1)]
// Set _a to the value of the last member + 1.
[_a = at_c<1>(_1) + 1]
% lit(',')) >
braceClose;

3

Решение

Основываясь на комментариях @llonesmiz, я нашел обходной путь. Основная проблема, по-видимому, заключается в том, что аргументы не передаются правильно во время вложенных действий (или что я делаю что-то в корне неправильно с boost :: phoenix):

PHX :: at_c<1> (phx :: insert (arg1, arg2)) (map, значение)

где действие возвращается at_c следует переслать карту двух аргументов и значение в действие, возвращаемое insert,

Напротив, следующее работает:

PHX :: at_c<1> (phx :: insert (arg1, arg2) (map, value)) ()

Тем не менее, в парсере boost :: spirit :: qi у меня нет прямого доступа к карте, потому что это одно из моих возвращаемых значений, и мне нужна ленивая оценка (в любом случае, в этом вся суть boost :: phoenix). Так что, похоже, он не применим напрямую к этому (упрощенному) правилу синтаксического анализа:

  enumeration = lit("enum") > typeName[at_c<0>(_val) = _1] > braceOpen >
// Initialize _a with 0.
eps[_a = 0] >
// Zero or one comma separated lists of members.
-(enumerationMember(_a)
// Only pass if the new member is unique.
[_pass = at_c<1>(insert(at_c<2>(_val), _1))] // <- Error
// Set _a to the value of the last member + 1.
[_a = at_c<1>(_1) + 1]
% lit(',')) >
braceClose;

Обходной путь, который я нашел, состоит в том, чтобы использовать два семантических действия и временно сохранить результат вставки в локальную переменную:

  enumeration = lit("enum") > typeName[at_c<0>(_val) = _1] > braceOpen >
// Initialize _a with 0.
eps[_a = 0] >
// Zero or one comma separated lists of members.
-(enumerationMember(_a)
// Temporarily store the result of insert into the local variable _b.
[_b = insert(at_c<2>(_val), _1)]
// Only pass if the previous insert was successful.
[_pass = at_c<1>(_b)]
// Set _a to the value of the last member + 1.
[_a = at_c<1>(_1) + 1]
% lit(',')) >
braceClose;

Определение правила по имени enumeration теперь выглядит так:

boost::spirit::qi::rule<Iterator, Enumeration(),
boost::spirit::qi::locals<
int, // _a
std::pair<std::map<std::string, int>::iterator, bool> // _b
>, space_type> enumeration;

Я думаю, что есть более элегантный способ, чем использование локального хранилища для результата вставки. Таким образом, я пока оставлю этот вопрос открытым, чтобы дать более элегантные ответы.

2

Другие решения

Других решений пока нет …