2016-09-17 49 views
1

讓我們考慮下面的代碼:如何在Boost.Phoenix中使用基於範圍的for_each?

#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中選擇,否則會與std版本發生衝突)。更何況,我必須保持無用big_ints_it變量!

還要注意,這跟在example provided by Phoenix documentation之後。

現在我試圖用for_eachmentioned 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>   ] 
… 

因爲StackOverflow上說,我甚至不能進入整個第一個錯誤,這個問題身體僅限於我已經進入他們的135034 30,000個字符...

回答

1

的問題是你的arg2使用在你的內心表達中。讓我們來看看這種情況。

您主要有:

- for_each(begin,end,outer_expr); 
- outer_expr=for_each(begin,end,inner_expr); 

兩個outer_exprinner_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 << "), "] 
     ) 
    ); 

全樣本(Running on WandBox)

#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表達式,這可能會導致更少的麻煩。

+0

哇!現在我讀了你的答案,我想知道我怎麼能沒有看到'arg2'的明顯問題!我在想什麼?!謝謝! –

+0

哦!至於編譯器和實際lambda表達式,你顯然是對的。然而,對於我最後的工作,我用舊編譯器堆棧。雖然問題的例子,我正在做一個不同的編譯器。 –