2017-03-07 5 views
2

値の配列を取得したいint buf[]={1...100}。私は、この配列は、variadicテンプレートを使用してコンパイル時に構築できることを願っています。これは、Python/Haskellなどのリストの理解のようなものです。C++ 14:variadicテンプレートを使用して値の配列を作成する方法1-100

しかし、C++ 11/14テンプレートはそれを行うことができますか? ありがとう

+0

は、グローバル名前空間でそれを行う方法を見ていないが、この配列は、ヘルパークラスの静的メンバとして宣言することができます。それでも、本当に単純に 'int'配列を初期化するのであれば、テンプレートを使いこなす代わりに、ソースコードを生成するためのスクリプトを書くだけです。あなたの宿題があなたの宿題をすることであるならば、あなたの宿題を行うためにstackoverflow.comの誰かにあなたを任せるのではなく、自分でそれを理解することがあなたのための全理由です。 –

答えて

4

C++ 14は、コンパイル時にループを許可します。

constexpr auto make_upto_100() { 
    std::array< int, 100 > ret = {}; 
    for (int i = 0; i != 100; ++ i) ret[i] = i + 1; 
    return ret; 
} 

C++ 11は、より多くのあなたの思考のようなものかもしれませんmake_index_sequenceのようなユーティリティを可能にします。 (C++ 14にもstd::[make_]index_sequenceを持っています。)

template< std::size_t ... i > 
struct index_sequence 
    { typedef index_sequence< i ..., sizeof ... (i) > next; }; 

template< std::size_t last > 
struct index_seq_maker 
    { typedef typename index_seq_maker< last - 1 >::type::next type; }; 

template<> 
struct index_seq_maker<0> 
    { typedef index_sequence<> type; }; 

template< std::size_t n > 
using make_index_sequence = typename index_seq_maker<n>::type; 

template< int ... i > 
constexpr 
std::array< int, 100 > 
make_upto_100(index_sequence< i ... >) 
    { return {{ i + 1 ... }}; } 

constexpr 
std::array< int, 100 > upto_100() = make_upto_100(make_index_sequence<100>{}); 
+0

@RyanHainingが修正されました。 – Potatoswatter

0

まあ、それはコンパイル時ではありませんが、通常、ほとんどのコードではstd::iotaを使用すると思います。実際には、コンパイル時の配列は実行可能ファイルの.dataセグメントに格納する必要があるため、コンパイル時のマジックよりも速い場合もあります。アレイのサイズが十分に大きい場合は、.dataから余分なディスクページを読み取ると、OSから新しく取り出された純粋メモリ内のページに書き込むよりも遅くなる可能性があります。

シンプルな使用法は次のようになります。

int buf[100]; 
std::iota(&buf[0], &buf[100], 1); 

率直に言って、私はここから始めたい、とだけあなたは、実行時の初期化で実績のあるパフォーマンスの問題を持っている場合は、テンプレートのマジックを見始めます。

1

これはC++ 14でも有効です。再帰的なテンプレートのインスタンス化によって、すべての値をconstexprとして初期化します。テンプレートパラメータを変更することで、順次値のサイズを必要なものに変更できるはずです。非常に大きな配列の場合、再帰制限に達する可能性があります。

#include <array> 

template<int NumVal, int ArrSize> 
constexpr void setVal(std::array<int, ArrSize> &constArr) { 
     std::get<NumVal>(constArr) = NumVal + 1; 
     if(NumVal) setVal<NumVal ? NumVal - 1 : 0, ArrSize>(constArr); 
} 

template<int ArrSize> 
constexpr auto arrRange() -> std::array<int, ArrSize> { 
     std::array<int, ArrSize> tmp{}; 
     setVal<ArrSize - 1, ArrSize>(tmp); 
     return tmp; 
} 

constexpr std::array<int, 100> constArr = arrRange<100>(); 

int main() { 
     for(int itr = 0; itr < 100; ++itr) printf("%d ", constArr[itr]); 
} 
3

これはコンパイル時に実際に設定されている場合は注意してください。あなたは

constexpr auto a = make_inc_array<100>(); // [1, 2, ..., 100] 

これは、リスト内包よりもはるかに少ない柔軟性があり、あなたはおそらくstd::iotaを使用してオフにずっといいよそして、あなたのサイズと呼んinteger_sequencestd::array

#include <utility> 
#include <array> 

template <int... Is> // when called below, Is will be 0 - N 
constexpr std::array<int, sizeof...(Is)> make_inc_array_impl(
    std::integer_sequence<int, Is...>) { 
    return {{(Is + 1)...}}; // +1 to start at one instead of [0, 1, ...] 
} 


template <std::size_t N> 
constexpr std::array<int, N> make_inc_array() { 
    return make_inc_array_impl(std::make_integer_sequence<int, N>{}); 
} 

でそれを行うことができます実行時に初期化します。

関連する問題