18

通常、私はboost::mpl::for_each<>()a をトラバースするために使用しますboost::mpl::vectorが、これには次のように宣言されたテンプレート関数を持つファンクターが必要です。

template<typename T> void operator()(T&){T::staticCall();}

これに関する私の問題は、オブジェクト T が によってインスタンス化されたくないということですfor_each<>。T パラメータはまったく必要ありませんoperator()for_each<>これを達成する方法はありますか、それともT 型のオブジェクトをテンプレート関数に渡さない代替手段はありますか?

最適には、operator() の定義を次のようにしたいと考えています。

template<typename T> void operator()(){T::staticCall();}

そしてもちろん、呼び出しの前に T をインスタンス化したくありません。その他のヒント/提案も大歓迎です。

4

6 に答える 6

14

同じ状況に遭遇し、共有したい問題に対して別の解決策を提供しました。それほど明白ではありませんが、既存のアルゴリズムを使用しています。アイデアは、代わりにポインターを使用することです。

typedef boost::mpl::vector<type1*, type2*> container;

struct functor
{
    template<typename T> void operator()(T*)
    {
        std::cout << "created " << typeid(T).name() << std::endl;
    }
};

int main()
{
    boost::mpl::for_each<container>(functor());
}

ここでは null ポインターを取得しますが、使用しないので気にしません。

前に述べたように、それはコードでは明らかではなく、おそらく追加のコメントが必要になるでしょうが、追加のコードを書かなくても問題は解決します。

追加した

ディエゴ・セビージャも似たようなことを提案したと思います。

于 2010-11-07T08:30:30.320 に答える
13

興味深い質問です!私が知る限り、Boost.MPL はそのようなアルゴリズムを提供していないようです。ただし、イテレータを使用して独自に記述することはそれほど難しくありません。

考えられる解決策は次のとおりです。

#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/next_prior.hpp>
#include <boost/mpl/vector.hpp>

using namespace boost::mpl;


namespace detail {

template < typename Begin, typename End, typename F >
struct static_for_each
{
    static void call( )
    {
        typedef typename Begin::type currentType;

        F::template call< currentType >();
        static_for_each< typename next< Begin >::type, End, F >::call();
    }
};


template < typename End, typename F >
struct static_for_each< End, End, F >
{
    static void call( )
    {
    }
};

} // namespace detail


template < typename Sequence, typename F >
void static_for_each( )
{
    typedef typename begin< Sequence >::type begin;
    typedef typename end< Sequence >::type   end;

    detail::static_for_each< begin, end, F >::call();
}

【ネーミングはあまり良くないかもしれませんが・・・】

このアルゴリズムの使用方法は次のとおりです。

struct Foo
{
    static void staticMemberFunction( )
    {
        std::cout << "Foo";
    }
};


struct Bar
{
    static void staticMemberFunction( )
    {
        std::cout << "Bar";
    }
};


struct CallStaticMemberFunction
{
    template < typename T >
    static void call()
    {
        T::staticMemberFunction();
    }
};


int main()
{
    typedef vector< Foo, Bar > sequence;

    static_for_each< sequence, CallStaticMemberFunction >(); // prints "FooBar"
}
于 2010-10-29T16:29:33.497 に答える
1

これは、 Luc Touraille の answerから非常にインスピレーションを得た代替ソリューションです。

このバージョンは、関数の代わりにMetafunction クラスstatic_for_eachを使用して行われます。これにより、関数スコープの外でも呼び出すことができます (実行時に不要な関数が呼び出されないように、コンパイル時にジョブを完全に実行する必要がある場合に役立ちます)。

firstさらに、とtypedefのおかげでより多くの対話lastが可能になり、必要に応じてループから情報を取得できるようになりreturnます。

Previousメタ関数クラスに渡される2 番目のテンプレート パラメーターのおかげで、各反復内で前の反復結果にアクセスすることもできますF

最後に、テンプレート パラメーターを使用してループ プロセスにデータを提供できます。これは、最初の反復Initialのパラメーターの値として与えられます。Previous

# include <boost/mpl/begin_end.hpp>
# include <boost/mpl/next_prior.hpp>
# include <boost/mpl/apply.hpp>

namespace detail_static_for_each
{
  // Loop
  template<typename Begin, typename End, typename F, typename Previous>
  struct static_for_each
  {
  private:
    typedef typename Begin::type                                current_type;

  public:
    typedef typename boost::mpl::apply<F, current_type, Previous>::type             first;
    typedef typename static_for_each<typename boost::mpl::next<Begin>::type, End, F, first>::last   last;
  };

  // End of loop
  template<typename End, typename F, typename Last>
  struct static_for_each<End, End, F, Last>
  {
  public:
    typedef Last    first;
    typedef Last    last;
  };

} // namespace detail_static_for_each

// Public interface
template<typename Sequence, typename F, typename Initial = void>
struct  static_for_each
{
private:
  typedef typename boost::mpl::begin<Sequence>::type        begin;
  typedef typename boost::mpl::end<Sequence>::type          end;

  typedef typename detail_static_for_each::static_for_each<begin, end, F, Initial>  loop;

public:
  typedef typename  loop::first                 first;
  typedef typename  loop::last                  last;
};

データの提供と取得の両方を行う簡単な例を次に示します。

# include <iostream>

# include <boost/type_traits/is_same.hpp>

# include <boost/mpl/if.hpp>
# include <boost/mpl/vector.hpp>

# include "static_for_each.hpp"

struct is_there_a_float                                                                                                                                                                                              
{                                                                                                                                                                                                                    
    template<typename currentItem, typename PreviousIterationType>                                                                                                                                                     
    struct apply                                                                                                                                                                                                       
    {                                                                                                                                                                                                                  
        typedef typename boost::mpl::if_< PreviousIterationType,                                                                                                                                                         
                                          PreviousIterationType,                                                                                                                                                         
                                          boost::is_same<float, currentItem> >::type    type;                                                                                                                        
    };                                                                                                                                                                                                                 
};

struct  test                                                                                                                                                                                                         
{                                                                                                                                                                                                                    
    typedef boost::mpl::vector< char, long, long, double, float, int, char > sequence;                                                                                                                                 

    typedef static_for_each<sequence, is_there_a_float, boost::false_type>::last    found;                                                                                                               
};

int     main(void)                                                                                                                                                                                                   
{                                                                                                                                                                                                                    
    std::cout << std::boolalpha << test::found::value << std::endl;                                                                                                                                                    

    return (0);                                                                                                                                                                                                        
}

これらの機能により、static_for_each一般的なランタイム ループ ( whileforBOOST_FOREACH ...) をより直接的に操作できるようになるため、 の使用がより類似したものになります。

于 2012-10-30T19:24:33.077 に答える
1

マーシン、あなたはとても正しいです。私はこれについて考えてきましたが、これに対する簡単な解決策は見当たりません。空の を書くことができなくてもoperator()、実際のオブジェクトが存在する必要のないポインターを使用することは少なくとも可能です。独自の実装を展開する必要があるようです。

于 2010-10-29T16:40:25.173 に答える
1

まず第一に、コード内の静的呼び出しは、オブジェクトが存在することを意味します。そういう意味ではビフォーアフターは無意味。「呼び出しの前に T をまったくインスタンス化したくない」という唯一の場合は、T がテンプレートの場合です。そうではありません。オブジェクトを存在させるのはその行であることは事実ですが、製品がコンパイルされるとそこに存在するだけではないと確信しています。

第二に、インスタンス化せずに for_each を使用する現在の方法があるとは思いません。IMHO これは、operator() を使用するという疑わしい決定によって引き起こされた MPL のバグです。私は開発者を知っていて、彼は私よりずっと賢いので、それが間違っているとは言いませんが、ここからあなたがこれを持ち出すのはそう思われます.

したがって、パラメーターを必要としないテンプレート化された関数を呼び出す for_each を作り直す必要があり、行き詰まっていると思います。私はそれが可能であるとほぼ確信していますが、MPL の既製のコンポーネントとしてすぐに利用できないことも同様に確信しています。

于 2010-10-29T16:27:56.580 に答える