2012-02-18 11 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すなわち、述語が生成するとして渡されたstd::is_base_ofall_ofへの最後の呼び出し偽です。なぜこれは機能しませんか? Apperently、基底クラスBは、述語に正しくバインドされません。どのようにバイナリ述語を渡すべきですか? mpl :: lambdaまたはmpl :: bindのいくつかの組み合わせ?リュックTourailleの優れた回答に基づいて

UPDATE

は、ここで追加ボーナスとして、私の質問にラムダを含まない溶液であるコンパイル時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を返すことがわかります。 –

+0

@Luc Touraille十分にテストすることはできません!私は否定的な結果もテストすべきだった。面白いことに、単項述語は真と二項述語に写像して偽に写像する。 – TemplateRex

答えて

1

を必要とするものである代わりにfoldfind_ifを使用してソリューションです:

#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に関連していると思うか分からない。明らかに、lambdaでサポートされているものよりも大きいapplyのアリティについての問題があります。とにかく、簡単な回避策は、applyの代わりにapply1を使用することです。ここでは完全な解決策は以下のとおりです。

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 :: lambda'が' mpl :: and_'の中にプレースホルダーをラップするのはまだ便利でしょうか? 'all_of'自体をラムダ式で渡したい場合に備えて?または、これは外の発信者が最善ですか? – TemplateRex

+0

ハム、私はこれが必要ではないと思います。それは、 'all_of'は引数やプレースホルダのどちらでも使用できるバイナリメタ関数です。私が知る限り、プレースホルダが矛盾することはありません。私はこれについて完全にはわかっていない、おそらく@JoelFalcouは確認することができますか? (Hi Joel、btw!) –

+1

私が正しく理解していれば、あなたの問題は[このスレッド](http://lists.boost.org/Archives/boost/2012/01/189614.php )、つまりネストされたプレースホルダー式。実際、 'is_pod'を用いた' all_of'のインスタンス化は 'fold 、_2>>'と同等でした。 2つの '_1'は同じ引数を参照することを意図していないため、' is_pod < _1 > 'を' lambda 'で保護する必要があります。 –

1

述語をラムダに変換する必要があります。そうでない場合、_1はPredに渡される最初のパラメータではなく、折り返しの最初のレベルとして解釈されます。 MPL ::ラムダは、あなたがここに

+0

ラムダはどこに挿入すればよいですか?コールサイトとall_ofの定義の両方で試しましたが、成功はありませんでした。なぜ、_1がパラメータとして渡されたとしても、単項述語is_podはそのまま動作しますか? – TemplateRex

関連する問題