2013-02-16 3 views
2

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

#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; 
+0

Я считаю, что вам следует использовать boost :: fusion :: at_c. Как [это] (http://liveworkspace.org/code/4C8nzP$4). – 2013-02-16 14:50:37

+0

Я не думаю, что это вариант, потому что не я называю объект-актер, а некоторое правило boost :: spirit :: qi parser. Я добавлю этот контекст к моему вопросу. – Stacker

+1

Правильно, тогда вы можете использовать его как [this] (http://liveworkspace.org/code/4C8nzP$5).Единственное изменение заключается в ограничении круглых скобок. В семантическом действии вам не понадобится '()' в конце. – 2013-02-16 15:49:01

ответ

2

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

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

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

В отличие от этого, следующий делает работу:

PHX :: at_c < 1> (PHX :: вставка (arg1, arg2) (карта, значение))()

Однако в подталкивание :: spirit :: qi parser У меня нет прямого доступа к карте, потому что это одно из моих возвращаемых значений, и мне нужна ленивая оценка (в любом случае это все-таки значение 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; 

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

+0

Прошу прощения, я не полностью понял ваш вопрос, когда я сделал эти комментарии. Теперь я вижу вашу проблему, и, боюсь, я не знаю, как ее решить. Надеюсь, кто-то, кто знает больше, поможет. Для «fun» я применил парсер enum, который не использует phoenix. Вы можете увидеть это [здесь] (http://liveworkspace.org/code/3KfI0r$5) (если вы измените окончательный цикл в конце, он должен скомпилировать без необходимости C++ 11). – 2013-02-16 19:27:06

+0

Ваши комментарии по-прежнему были полезными, спасибо :) Глядя на ваш подход, я не совсем уверен, является ли это хорошим решением поставить логику в структуры AST или лучше сохранить как можно больше в правилах парсера. Я вижу несколько плюсов и минусов для обоих подходов. Ну, мне нужно получить больше опыта с boost :: spirit & co, сейчас я все еще на «экспериментальной стадии» :) – Stacker

+0

Смотрите, нравится ли вам [эта версия] (http://liveworkspace.org/code/ 3KfI0r $ 7). – 2013-02-16 20:29:38

Смежные вопросы