2012-05-31 2 views
5

C++ 11で、私は私が値でブースト::配列の内容を初期化したいコピーMPL :: vector_c、コンパイル時に静的な配列へ

#include <boost/mpl/vector_c.hpp> 
#include <boost/mpl/size.hpp> 

#include <boost/array.hpp> 

#include <iostream> 

namespace mpl = boost::mpl; 

template<std::size_t ... Args> 
struct Test 
{ 
      typedef mpl::vector_c<std::size_t, Args ...> values_type; 

      static const boost::array<std::size_t, sizeof...(Args)> values; 
}; 


int main (int argc, char** argv) 
{ 
      Test<3,2,5,6,7> test; 
      return 0; 
} 

のようなものは、「含まれる」を持ちますmpl :: vector_cに入れてください。この初期化は、コンパイル時に実行する必要があります。私はプリプロセッサを使っていくつかの解決策を見てきましたが、私はvariadicテンプレートの場合にそれらをどのように適用するかについて考えていません。

上記のサンプルコードでは、mpl :: vector_cの要素はTestのテンプレートパラメータと同じであることに注意してください。実際のコードでは、ではなく、values_typeの長さはテンプレート引数の数になりますが、実際の値はmplアルゴリズムのシーケンスを適用した結果になります。したがって、引数が同じであると仮定しないでください。

質問がクリアなので、ありがとう!

答えて

7

at_cを使用してvector_cをパラメータパックに抽出し、それを展開して使用して配列を初期化します。

#include <cstdio> 
#include <array> 
#include <boost/mpl/vector_c.hpp> 
#include <boost/mpl/at.hpp> 
#include <boost/mpl/size.hpp> 
#include <utils/vtmp.hpp> 
//^https://github.com/kennytm/utils/blob/master/vtmp.hpp 

template <typename MPLVectorType> 
class to_std_array 
{ 
    typedef typename MPLVectorType::value_type element_type; 
    static constexpr size_t length = boost::mpl::size<MPLVectorType>::value; 
    typedef std::array<element_type, length> array_type; 

    template <size_t... indices> 
    static constexpr array_type 
      make(const utils::vtmp::integers<indices...>&) noexcept 
    { 
     return array_type{{ 
      boost::mpl::at_c<MPLVectorType, indices>::type::value... 
     }}; 
    } 

public: 
    static constexpr array_type make() noexcept 
    { 
     return make(utils::vtmp::iota<length>{}); 
    } 
}; 

int main() 
{ 
    typedef boost::mpl::vector_c<size_t, 3, 2, 5, 6, 7> values; 

    for (size_t s : to_std_array<values>::make()) 
     printf("%zu\n", s); 
    return 0; 
} 

私はここstd::arrayを使用していますが、あなたは単にboost::arrayにそれを変更することができますし、それはまだ動作します。 make()機能がconstexprであるため、表現

to_std_array<MPLVector>::make() 

は、コンパイル時に実行されます。


同じ技術は通常、関数呼び出し("unpacking" a tuple to call a matching function pointer)に、std::arrayConvert std::tuple to std::array C++11)にstd::tupleの拡大に使用されているなど

+0

私は 'に比べてどんな利点があるかどうかについての単なる好奇心for(size_t s:{3、2、5、6、7}) '? – betabandido

+0

@betabandido:いいえ、どちらも同じアセンブリにコンパイルされます(もちろん最適化後)。 – kennytm

+0

しかし、テンプレートメタプログラミングのより複雑な使い方では、質問とあなたのソリューションに示されているアプローチが実際には必要かもしれないと思いますよね?例えば、私は配列をある関数から別の関数に渡す必要がある状況を考えています。その場合でもプレーンな配列({3,2、...})を使うことは可能でしょうか? – betabandido