如何在 Boost.Phoenix 中使用基于范围的 for_each?
How to use range-based for_each in Boost.Phoenix?
让我们考虑以下代码:
#include <boost/phoenix.hpp>
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> const small_ints {1, 2, 3, 4, 5};
std::vector<int> const big_ints {11, 12, 13, 14, 15};
namespace phoenix = boost::phoenix;
using namespace boost::phoenix;
using namespace boost::phoenix::placeholders;
std::vector<int>::const_iterator big_ints_it;
std::for_each(small_ints.cbegin(), small_ints.cend(),
for_(phoenix::ref(big_ints_it) = begin(phoenix::cref(big_ints)), phoenix::ref(big_ints_it) != end(phoenix::cref(big_ints)), ++phoenix::ref(big_ints_it))
[
std::cout << val('(') << arg1 << ',' << *phoenix::ref(big_ints_it) << "), "
]
);
}
通过打印预期的对序列可以正常工作
(1,11), (1,12), (1,13), (1,14), (1,15), (2,11), (2,12), …, (5,14), (5,15),
这只是两次迭代的笛卡尔积。
不过for_
太丑了!查看所有这些 ref
、cref
(不知何故我总是必须从 phoenix
明确地 select 否则会与 std
版本发生冲突)。更何况我还得保留无用的big_ints_it
变量!
另请注意,这遵循 example provided by Phoenix documentation 本身。
现在我尝试使用 for_each
mentioned along iteration algorithms,期待更简单的版本:
std::for_each(small_ints.cbegin(), small_ints.cend(),
for_each(phoenix::cref(big_ints),
std::cout << val('(') << arg1 << ", " << arg2 << "), "
)
);
但它甚至无法编译!或者至少使用 Visual Studio 2013 和 Boost 1.61。
我遇到了多个错误。首先是
1>c:\programming\boost_1_61_0\boost\proto\detail\poly_function.hpp(205): error C2039: 'type' : is not a member of 'boost::proto::functional::at::result<Sig>'
1> with
1> [
1> Sig=boost::proto::functional::at (boost::phoenix::vector2<const 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::impl::for_each>,0>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::reference_wrapper<const std::vector<int,std::allocator<int>>>>,0>>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::shift_left,boost::proto::argsns_::list2<boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::shift_left,boost::proto::argsns_::list2<boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::shift_left,boost::proto::argsns_::list2<boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::shift_left,boost::proto::argsns_::list2<boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::shift_left,boost::proto::argsns_::list2<boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<std::basic_ostream<char,std::char_traits<char>> &>,0>>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<char>,0>>>,2>>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::phoenix::argument<1>>,0>>>,2>>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<char [3]>,0>>>,2>>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::phoenix::argument<2>>,0>>>,2>>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<char [4]>,0>>>,2>>>,3>> *,const int &> &,boost::mpl::int_<2>)
1> ]
…
我什至无法输入整个第一个错误,因为 Whosebug 说,问题正文限制为 30,000 个字符,我输入了其中的 135,034 个字符......
问题是你在内心表达中使用了arg2
。来看看情况吧
你基本上有:
- for_each(begin,end,outer_expr);
- outer_expr=for_each(begin,end,inner_expr);
outer_expr
和 inner_expr
都是采用单个参数(其各自向量的一个元素)的 lambda 表达式。
您需要的是一种将参数从 outer_expr
传递到 inner_expr
的方法。幸运的是 Boost.Phoenix 提供了一种简单的方法来做到这一点:boost::phoenix::lambda
:
std::for_each(small_ints.cbegin(), small_ints.cend(),
phx::for_each(phx::cref(big_ints),
phx::lambda(_a=arg1)[phx::ref(std::cout) << '(' << _a << ", " << arg1 << "), "]
)
);
或者变得有点傻,但可能有助于提高可读性:
boost::phoenix::placeholders::arg1_type current_small_int, current_big_int;
boost::phoenix::local_names::_a_type passed_small_int;
std::for_each(small_ints.cbegin(), small_ints.cend(),
phx::for_each(phx::cref(big_ints),
phx::lambda(passed_small_int=current_small_int)[phx::ref(std::cout) << '(' << passed_small_int << ", " << current_big_int << "), "]
)
);
#include <iostream>
#include <algorithm>
#include <vector>
#include <boost/phoenix.hpp>
int main()
{
std::vector<int> const small_ints {1, 2, 3, 4, 5};
std::vector<int> const big_ints {11, 12, 13, 14, 15};
namespace phx = boost::phoenix;
using boost::phoenix::placeholders::arg1;
using boost::phoenix::local_names::_a;
std::vector<int>::const_iterator big_ints_it;
std::for_each(small_ints.cbegin(), small_ints.cend(),
phx::for_each(phx::cref(big_ints),
phx::lambda(_a=arg1)[phx::ref(std::cout) << '(' << _a << ", " << arg1 << "), "]
)
);
}
PS:如果您的编译器可以像这样初始化向量,它应该能够使用实际的 lambda 表达式,这可能会减少麻烦。
让我们考虑以下代码:
#include <boost/phoenix.hpp>
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> const small_ints {1, 2, 3, 4, 5};
std::vector<int> const big_ints {11, 12, 13, 14, 15};
namespace phoenix = boost::phoenix;
using namespace boost::phoenix;
using namespace boost::phoenix::placeholders;
std::vector<int>::const_iterator big_ints_it;
std::for_each(small_ints.cbegin(), small_ints.cend(),
for_(phoenix::ref(big_ints_it) = begin(phoenix::cref(big_ints)), phoenix::ref(big_ints_it) != end(phoenix::cref(big_ints)), ++phoenix::ref(big_ints_it))
[
std::cout << val('(') << arg1 << ',' << *phoenix::ref(big_ints_it) << "), "
]
);
}
通过打印预期的对序列可以正常工作
(1,11), (1,12), (1,13), (1,14), (1,15), (2,11), (2,12), …, (5,14), (5,15),
这只是两次迭代的笛卡尔积。
不过for_
太丑了!查看所有这些 ref
、cref
(不知何故我总是必须从 phoenix
明确地 select 否则会与 std
版本发生冲突)。更何况我还得保留无用的big_ints_it
变量!
另请注意,这遵循 example provided by Phoenix documentation 本身。
现在我尝试使用 for_each
mentioned along iteration algorithms,期待更简单的版本:
std::for_each(small_ints.cbegin(), small_ints.cend(),
for_each(phoenix::cref(big_ints),
std::cout << val('(') << arg1 << ", " << arg2 << "), "
)
);
但它甚至无法编译!或者至少使用 Visual Studio 2013 和 Boost 1.61。
我遇到了多个错误。首先是
1>c:\programming\boost_1_61_0\boost\proto\detail\poly_function.hpp(205): error C2039: 'type' : is not a member of 'boost::proto::functional::at::result<Sig>'
1> with
1> [
1> Sig=boost::proto::functional::at (boost::phoenix::vector2<const 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::impl::for_each>,0>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::reference_wrapper<const std::vector<int,std::allocator<int>>>>,0>>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::shift_left,boost::proto::argsns_::list2<boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::shift_left,boost::proto::argsns_::list2<boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::shift_left,boost::proto::argsns_::list2<boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::shift_left,boost::proto::argsns_::list2<boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::shift_left,boost::proto::argsns_::list2<boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<std::basic_ostream<char,std::char_traits<char>> &>,0>>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<char>,0>>>,2>>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::phoenix::argument<1>>,0>>>,2>>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<char [3]>,0>>>,2>>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::phoenix::argument<2>>,0>>>,2>>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<char [4]>,0>>>,2>>>,3>> *,const int &> &,boost::mpl::int_<2>)
1> ]
…
我什至无法输入整个第一个错误,因为 Whosebug 说,问题正文限制为 30,000 个字符,我输入了其中的 135,034 个字符......
问题是你在内心表达中使用了arg2
。来看看情况吧
你基本上有:
- for_each(begin,end,outer_expr);
- outer_expr=for_each(begin,end,inner_expr);
outer_expr
和 inner_expr
都是采用单个参数(其各自向量的一个元素)的 lambda 表达式。
您需要的是一种将参数从 outer_expr
传递到 inner_expr
的方法。幸运的是 Boost.Phoenix 提供了一种简单的方法来做到这一点:boost::phoenix::lambda
:
std::for_each(small_ints.cbegin(), small_ints.cend(),
phx::for_each(phx::cref(big_ints),
phx::lambda(_a=arg1)[phx::ref(std::cout) << '(' << _a << ", " << arg1 << "), "]
)
);
或者变得有点傻,但可能有助于提高可读性:
boost::phoenix::placeholders::arg1_type current_small_int, current_big_int;
boost::phoenix::local_names::_a_type passed_small_int;
std::for_each(small_ints.cbegin(), small_ints.cend(),
phx::for_each(phx::cref(big_ints),
phx::lambda(passed_small_int=current_small_int)[phx::ref(std::cout) << '(' << passed_small_int << ", " << current_big_int << "), "]
)
);
#include <iostream>
#include <algorithm>
#include <vector>
#include <boost/phoenix.hpp>
int main()
{
std::vector<int> const small_ints {1, 2, 3, 4, 5};
std::vector<int> const big_ints {11, 12, 13, 14, 15};
namespace phx = boost::phoenix;
using boost::phoenix::placeholders::arg1;
using boost::phoenix::local_names::_a;
std::vector<int>::const_iterator big_ints_it;
std::for_each(small_ints.cbegin(), small_ints.cend(),
phx::for_each(phx::cref(big_ints),
phx::lambda(_a=arg1)[phx::ref(std::cout) << '(' << _a << ", " << arg1 << "), "]
)
);
}
PS:如果您的编译器可以像这样初始化向量,它应该能够使用实际的 lambda 表达式,这可能会减少麻烦。