3

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

1 回答 1

2

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

phx::at_c<1>(phx::insert(arg1, arg2))(地图, 值)

其中由返回的动作at_c应该将两个参数映射和值转发给由返回的动作insert

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

phx::at_c<1>(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;

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

  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;

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

于 2013-02-16T17:12:07.567 回答