25

最近これに遭遇しましたが、言語が b = c; を許可する理由がわかりませんでした。以下で、b = {3, 4} に失敗します。後者を許可することに問題はありますか?

struct T {
    int x;
    int y;
};

int main()
{
    T a = {1, 2};
    T b;

    b = {3, 4}; // why does this fail ?

    T c = {3, 4};
    b = c; // this works

    return 0;
}
4

3 に答える 3

37

は有効な初期化子ですが、式ではないため失敗します{3, 4}(少なくとも C ではありません。C++ の詳細については以下を参照してください)。

C のすべての式には、式自体を調べることで判別できる型があります。、 or (配列型)、または無数の他の型のいずれかである{3, 4}可能性があります。struct Tint[2]

C99 では、複合リテラルと呼ばれる新しい機能が追加されました。これは、初期化子と同様の構文を使用しますが、式を作成して型を指定できます。

b = (struct T){3, 4};

はキャスト演算子で(struct T)ないことに注意してください。これは、複合リテラルの構文の一部です。

複合リテラルの詳細については、ドラフト C11 標準のセクション 6.5.2.5 を参照してください。

複合リテラルは、1999 年の ISO C 標準 (C99) で導入されました。コンパイラが C99 以上をサポートしていない場合 (*咳*マイクロソフト*咳*)、それらを使用することはできません。

C++ (別の言語であることを忘れないでください) を使用している場合、複合リテラルはサポートされていませんが、別の方法がある可能性があります。Potatoswatter がコメントで指摘しているように、これは次のとおりです。

b = T{3, 4};

は C++11 で有効です (ただし、以前のバージョンの C++ 言語では有効ではありません)。これは、C++ 標準のセクション 5.2.3 [expr.type.conf] で説明されています。

さらに言えば、これは:

b = {3, 4};

も有効な C++11 構文です。この形式は、割り当ての右側を含む、指定された多くのコンテキストで使用できます。これは、C++ 標準のセクション 8.5.4 [dcl.init.list] で説明されています。

C++ 標準の最近のドラフトの 1 つが N3485 です。

(g++ は、拡張機能として C++ の C99 スタイルの複合リテラルをサポートします。)

また、C99 より前のコンパイラに行き詰まっている場合は、次のような独自の初期化関数をいつでも作成できます。

struct T init_T(int x, int y) {
    struct T result;
    result.x = x;
    result.y = y;
    return result;
}

/* ... */

struct T obj;
/* ... */
obj = init_T(3, 4);

これは煩わしい余分な作業です (C99 が複合リテラルを追加したのはそのためです) が、これで十分です。一方、ほとんどの場合、おそらく初期化を使用する方がよいでしょう:

struct T obj;
/* ... */
{
    struct T tmp = { 3, 4 };
    obj = tmp;
}

どちらが優れているかは、おそらくプログラムの構造によって異なります。

于 2013-08-20T00:28:36.377 に答える
6

正しい C99 または C11 の「複合リテラル」表記を使用しなかったためです。

b = (struct T){ 3, 4 };

詳細については、ISO/IEC 9899:2011 の§6.5.2 後置演算子および §6.5.2.5複合リテラルを参照してください。

( type-name ) { initializer-list }
( type-name ) { initializer-list , }

于 2013-08-20T00:28:14.340 に答える
0

それは言語の定義だからです...「これを許可するコンパイラを書くのが難しくなる」以外に特別な理由はないと思います。

b = T{3, 4}C++ 11 コンパイラがあれば実行できます。

于 2013-08-20T00:31:16.030 に答える