2012-02-18 50 views
1

考慮在std::any_of應如何將二元謂詞傳遞給用戶定義的Boost.MPL算法?

#include <iostream>      // cout 
    #include <type_traits>     // is_base_of, is_pod 
    #include <boost/mpl/apply.hpp>   // apply 
    #include <boost/mpl/fold.hpp>   // fold 
    #include <boost/mpl/lambda.hpp>   // lambda, _1, _2 
    #include <boost/mpl/logical.hpp>  // and_, true_ 
    #include <boost/mpl/vector.hpp>   // vector 

    template 
    < 
      typename Sequence, 
      typename Pred 
    > 
    struct all_of 
    : 
      boost::mpl::fold< 
        Sequence, 
        boost::mpl::true_, 
        boost::mpl::lambda< 
          boost::mpl::and_< 
            boost::mpl::_1, 
            boost::mpl::apply< Pred, boost::mpl::_2 > 
          > 
        > 
      > 
    {}; 

    typedef int P1; typedef char P2; typedef float P3; 

    typedef boost::mpl::vector< 
      P1, P2, P3 
    > pod_types; 

    struct B {}; struct D1: B {}; struct D2: B {}; struct D3: B {}; 

    typedef boost::mpl::vector< 
      D1, D2, D3 
    > derived_types; 

    int main() 
    { 
      std::cout << (std::is_pod<P1>::value) << '\n'; // true 
      std::cout << (std::is_pod<P2>::value) << '\n'; // true 
      std::cout << (std::is_pod<P3>::value) << '\n'; // true  

      std::cout << (
        all_of< 
          pod_types, 
          std::is_pod<boost::mpl::_1>       
        >::type::value // true 
      ) << '\n'; 

      std::cout << (std::is_base_of<B, D1>::value) << '\n'; // true 
      std::cout << (std::is_base_of<B, D2>::value) << '\n'; // true 
      std::cout << (std::is_base_of<B, D3>::value) << '\n'; // true 

      std::cout << (
        all_of< 
          derived_types, 
          std::is_base_of< B, boost::mpl::_1 >  
        >::type::value // false (but should be true) 
      ) << '\n'; 

      return 0; 
    } 

一個Boost.MPL風格的元編程版本以下嘗試這種打印出:1 1 1 1 1 1 1 0。即,all_of最後調用與std::is_base_of作謂語通過生成假。爲什麼這不起作用?顯然,基類B沒有得到正確的綁定到謂詞。我應該如何傳遞一個二元謂詞? mpl :: lambda或mpl :: bind的組合?

UPDATE

基於呂克Touraille的出色答卷,這裏是免費的λ-解決我的問題,以作爲一個額外的獎金none_of編譯時的版本和any_of

template<typename Sequence, typename Pred> 
    struct all_of 
    : 
      std::is_same< typename 
        boost::mpl::find_if< 
          Sequence, 
          boost::mpl::not_<Pred> 
        >::type, typename 
        boost::mpl::end<Sequence>::type 
      > 
    {}; 

    template<typename Sequence, typename Pred> 
    struct none_of 
    : 
      all_of< Sequence, boost::mpl::not_<Pred> > 
    {}; 

    template<typename Sequence, typename Pred> 
    struct any_of 
    : 
      boost::mpl::not_< none_of< Sequence, Pred > > 
    {}; 
+1

它不會在第一種情況下工作之一:如果您在'pod_types'添加非莢,你會看到'all_of '仍然返回true 。 – 2012-02-22 08:24:06

+0

@Luc Touraille一個永遠不能測試的足夠!我也應該測試一個消極的結果。有趣的是,一元謂詞映射爲真,二元謂詞映射爲假。 – TemplateRex 2012-02-22 10:32:09

回答

1

下面是一個解決方案使用find_if代替fold

#include <type_traits> 
#include <boost/mpl/end.hpp> 
#include <boost/mpl/find_if.hpp> 
#include <boost/mpl/logical.hpp> 

template 
< 
    typename Sequence, 
    typename Pred 
> 
struct all_of 
: 
    std::is_same< typename 
     boost::mpl::end<Sequence>::type, typename 
     boost::mpl::find_if< 
      Sequence, 
      boost::mpl::not_<Pred> 
     >::type 
    > 
{}; 

如果你要堅持fold,你需要把謂語變成使用lambda元函數調用前,以protect參數:

boost::mpl::apply< typename 
    boost::mpl::lambda<Pred>::type, 
    boost::mpl::_2 
> 

然而,你會注意到,這將不能工作。我不確定爲什麼,我認爲它與this discussion on the Boost mailing list有關。顯然,apply的數量大於lambda所支持的數量。無論如何,一個簡單的解決方法是使用apply1而不是apply。以下是完整的解決方案:

template 
< 
     typename Sequence, 
     typename Pred 
> 
struct all_of 
    : boost::mpl::fold< 
     Sequence, 
     boost::mpl::true_, 
     boost::mpl::and_< 
      boost::mpl::_1, 
      boost::mpl::apply1< typename 
       boost::mpl::lambda<Pred>::type, 
       boost::mpl::_2 
      > 
     > 
    > 
{}; 
+0

謝謝!這是我正在尋找的。在上面的代碼中'mpl :: and_'包含'mpl :: lambda'佔位符是不是很方便?以防萬一你想在lambda表達式中傳遞'all_of'本身?或者這最好由外部來電者完成? – TemplateRex 2012-02-22 10:35:48

+0

嗯,我不認爲這是必要的。因爲它是'all_of'是一個二元元函數像任何其他,可以使用參數或佔位符。據我所知,沒有衝突佔位符的風險。我對此不完全確定,或許@JoelFalcou可以證實? (嗨喬爾,順便說一句!) – 2012-02-22 11:02:05

+1

如果我理解正確,你遇到的問題是類似於[這個線程]中描述的問題(http://lists.boost.org/Archives/boost/2012/01/189614.php ),即嵌套的佔位符表達式。實際上,用'is_pod'實例化'all_of'就相當於'fold ,_2>>>'。兩個'_1'並不是指相同的參數,因此需要用'lambda'保護'is_pod < _1 >'。 – 2012-02-22 13:05:12

1

您需要將謂詞轉換爲lambda或_1將被解釋爲摺疊的第一級調用,而不是要傳遞給Pred的第一個參數。 MPL ::拉姆達是你所需要的

+0

應該在哪裏插入lambda?我在呼叫站點和all_of的定義都試過,但沒有成功。那麼爲什麼一元謂詞is_pod可以正常工作,即使使用_1作爲參數傳遞? – TemplateRex 2012-02-19 21:30:35

相關問題