web-dev-qa-db-ja.com

c ++メンバーとして配列を持つ構造体の初期化

元々、実行時ではなくコンパイル時に配列を初期化しようとしていることが明確ではなかったため、再び編集されました...


次の縮小テストケースがあります。

typedef struct TestStruct
{
    int length;
    int values[];
};

TestStruct t = {3, {0, 1, 2}};
TestStruct t2 = {4, {0, 1, 2, 3}};

int main()
{
    return(0);
}

これはVisual C++で動作しますが、Linuxではg ++でコンパイルしません。この特定の種類の初期化子を移植可能にするのを手伝ってくれる人はいますか?

追加の詳細:作業している実際の構造には他のint値がいくつかあり、配列の長さは1つのエントリから1800を超えるエントリまで可能です。

編集:これはVLAの問題ではないと思います(しかし確信はありません)。明確にするために、私はコンパイラーにコンパイル時に作業を行わせようとしています。実行時の配列の長さは一定です。私が間違っている場合はおologiesびします。私は主にこのレガシーアプリのメンテナンスにこだわっているc#/ Perl/Rubyプログラマーです...

助けていただければ幸いです。ありがとう!

24
Drew Shafer

c ++には、c99の最後の要素と同じ柔軟な配列メンバーがありません。要素の数がわからない場合はstd::vectorを使用するか、要素の数を指定する必要があります。

EDIT:配列はランタイム定数であると編集で述べているので、サイズを指定すればうまく動作するはずです。 g ++は、次のコードには問題ありません。

struct TestStruct { // note typedef is not needed */
    int length;
    int values[3]; // specified the size
};

TestStruct t = {3, {0, 1, 2}};

int main() {
    // main implicitly returns 0 if none specified
}

編集:コメントに対処するには、次のようなテンプレートを使用できます。

template <int N>
struct TestStruct {
    int length;
    int values[N];
};

TestStruct<3> t3 = {3, {0, 1, 2}};
TestStruct<2> t2 = {2, {0, 1}};

int main() {}

唯一の問題は、t2とt3の両方をコンテナー(list/vector/stack/queue/etcなど)に入れる簡単な方法がないことです。サイズが異なるため、std::vectorを使用する必要があります。また、それを行う場合、サイズを保存する必要はありません(サイズに関連付けられています)。

template <int N>
struct TestStruct {
    static const int length = N;
    int values[N];
};

TestStruct<3> t3 = {{0, 1, 2}};
TestStruct<2> t2 = {{0, 1}};

int main() {}

しかし、もう一度、t2とt3を「コレクション」に簡単にまとめることはできません。

編集:全体として、(いくつかの数字とサイズよりも多くのデータを保存しない限り)構造体をまったく必要とせず、単純な古いベクトルを使用することはできないようです。

typedef std::vector<int> TestStruct;


int t2_init[] = { 0, 1, 2 };
TestStruct t3(t3_init, t3_init + 3);

int t2_init[] = { 0, 1 };
TestStruct t2(t2_init, t2_init + 2);

int main() {}

これにより、t2とt3の両方をコレクションに含めることができます。残念ながらstd::vectorには(まだ)配列スタイルの初期化構文がないため、ショートカットを使用しました。しかし、ニースの方法でベクトルを取り込む関数を書くのは十分簡単です。

EDIT: OK、コレクションは必要ありませんが、コレクションを関数に渡す必要があります。テンプレートを使用してタイプセーフを維持できます。

template <int N>
struct TestStruct {
    static const int length = N;
    int values[N];
};

TestStruct<3> t3 = {{0, 1, 2}};
TestStruct<2> t2 = {{0, 1}};

template <int N>
void func(const TestStruct<N> &ts) { /* you could make it non-const if you need it to modify the ts */
    for(int i = 0; i < N; ++i) { /* we could also use ts.length instead of N here */
        std::cout << ts.values[i] << std::endl;
    }
}

// this will work too...
template <class T>
void func2(const T &ts) { 
    for(int i = 0; i < ts.length; ++i) {
        std::cout << ts.values[i] << std::endl;
    }
}

int main() {
    func(t2);
    func(t3);
    func2(t2);
}
26
Evan Teran

GCC/Clangは次の拡張機能をサポートします

 
 typedef struct TestStruct 
 {
 int length; 
 int *値; 
}; 
 
 TestStruct t = {3、(int []){0、1、2}}; 
 TestStruct t2 = {4、(int []){0、1、2、3}}; 
 
3
zufuliu
struct TestStruct {
    int length;
    const int *values;
};

static const uint8_t TEST_STRUCT_VAL_1[] = {0, 1, 2};
const TestStruct t1 = {3, TEST_STRUCT_VAL_1};

static const uint8_t TEST_STRUCT_VAL_2[] = {0, 1, 2, 3};
const TestStruct t2 = {4, TEST_STRUCT_VAL_2};`

私の場合、gcc/g ++を使用したstm32プログラミングでは、値の配列は生データストレージのみであるため、静的constであり、フラッシュに格納されます。この方法を使用して、液晶ディスプレイのフォントパターンを保存します。

テンプレートを使用すると、「節約」と入力されますが、サイズは節約されません。

1
aGuegu

[〜#〜] vla [〜#〜] はC99でのみサポートされています。 C++はそれをサポートしていません。 http://gcc.gnu.org/c99status.html から、gccは現在VLAをサポートしています。

0
tristan