评估boost :: phoenix :: insert的结果

时间:2013-02-16 14:28:30

标签: c++ boost boost-fusion boost-phoenix

我在尝试评估将元素插入地图的boost::phoenix::insert的结果时遇到了困难。与常规std::map::insert类似,boost::phoenix::insert返回的actor对象也返回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和boost 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.

我即将用尽如何正确评估插入结果的想法。任何帮助将不胜感激。

编辑: 我的问题的更广泛的背景是我正在尝试使用boost :: spirit :: qi解析类似C ++的枚举。我发现尝试实现相同目的的任何示例都不会检查重复的枚举成员。这里有一个代码片段,其中包含两个相关规则:

  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;

1 个答案:

答案 0 :(得分:2)

根据@llonesmiz的评论,我找到了一个解决方法。核心问题似乎是在整个嵌套动作中没有正确传递参数(或者我正在做一些与boost :: phoenix根本错误的事情):

phx :: at_c&lt; 1&gt;(phx :: insert(arg1,arg2))(map,value)

at_c返回的操作应将两个参数map和value转发给insert返回的操作。

相反,以下方法确实有效:

phx :: at_c&lt; 1&gt;(phx :: insert(arg1,arg2)(map,value))()

然而,在boost :: spirit :: qi解析器中,我没有直接访问map,因为它是我的返回值之一,我需要懒惰的评估(无论如何这都是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;

我找到的解决方法是使用两个语义操作并将insert的结果临时存储到局部变量中:

  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;

我想有一些比使用本地存储更优雅的方式来插入结果。因此,我将暂时保持这个问题,以便提供更优雅的答案。