9

目標:オブジェクトをリスト初期化できるようにし、デフォルトの初期化ですべてのPODを0/に初期化falseし、定型文をできるだけ少なくする(C ++ 11)。

いくつかのPODを持ついくつかのクラスがあると仮定します(ファイル形式の解析を考えてください)。未定義の値を処理しないために、デフォルトの構築オブジェクトを0に値初期化する必要があります。たとえば、すべてのメンバーに明示的に名前を付ける場合と同様に、このような場合に正常に機能する独自のデフォルトmemset()のC'torを提供します。this

ただし、これは定型文です。さらに重要なことに、引数のない独自のデフォルトコンストラクターを提供すると、メンバーの初期化にリスト初期化構文を使用できなくなります。

class Fails1 {
public:
  int a, b;
  Fails1() { memset(this, 0, sizeof(*this)); }
};

Fails1 this_works;
Fails1 this_fails{ 42, 54 }; // compiler error

のコンストラクターを追加することもできinitializer_listますが、それはさらに定型的なものです。ボイラープレートをすべて避けたい。

そこで、ユーザーが提供するデフォルトコンストラクターがない場合に、コンパイラーによって提供されるデフォルトコンストラクターを、さまざまなメソッドと組み合わせて初期化する方法を調べました。これが私が完全に混乱したところです:

class A {
public:
  int a, b;
};

このクラスを使用すると、両方のコンストラクターを自分で提供しなくても、空の初期化リストと値を持つリストの両方を使用できます。それは私が欲しいものの一部です。

// Example 1: default initialization
A a1;

最初の例では初期化を使用しています。メンバーaであり、b後で未定義になります(私が望むものではなく、値を初期化する必要があります)。

// Example 2: Value-initialization, so this works, I guess:
A a2 = A();

例2は値の初期化を使用し、後でコピーしません。それが私が望んでいることですが、空のbrace-init-listsでも同じことができると思いました。次の例を参照してください。

// Example 3: list-initialization with empty brace-init-list
A a3{};

例3は、私がそのトリックを実行すると思ったものです。空のbrace-init-listを使用したリストの初期化については、8.5.4「リストの初期化」で説明しています。特に8.5.4.3は、「初期化子リストに要素がなく、Tがデフォルトのコンストラクターを持つクラス型である場合、objectvalue-initialized」と述べています。ただし、これにより、g++4.7.2で次の警告が発生します-Wextra

missing initializer for member ‘A::a’ [-Wmissing-field-initializers]
missing initializer for member ‘A::b’ [-Wmissing-field-initializers]

ただし、clang ++ 3.1による警告はないため、g++のバグである可能性もあります。

では、元の質問に戻りましょう。initializer_list独自のボイラープラットフォームのデフォルトコンストラクターを提供せずにオブジェクトを値初期化するにはどうすればよいですか?独自のコンストラクターを提供せずにメンバーのリスト初期化を使用する機能を維持しながら?

4

2 に答える 2

8

次のような単純な構造体

struct A { int a,b; };

すでに引用されている§8.5.4/3で説明されているように、明らかに集約であり、A a {};明らかに集約の初期化であり、値の初期化(つまり、ゼロの初期化)を意味します。(特に、次の段落にある例に注意してください。これは、実際にはあなたの状況と同じです。)

GCC の警告は非常に誤解を招くものです。

既存のバグ レポートを検索しているときに、あなたが自分で提出したものを見つけました。それは正しいことだったと思います。

あなたはすでに関連する標準セクションを作成しており、他のさまざまな人々がコメントに貢献しているので、これをコミュニティ Wiki の回答にします。

于 2012-12-25T14:37:05.630 に答える
4

初期化子の欠落に関するgccの警告は、他の何よりも不利益です。初期化子リストがある場合、値はリストから入力され、残りのフィールドはゼロで初期化されます。したがって、初期化子リストが空の場合、すべての値はゼロで初期化されます。すべてのメンバーに言及していない空でない初期化子リストについて警告するのは合理的かもしれません:プログラマーが配列の最初の要素にゼロ以外の初期化子を提供し、初期化子が残りのすべての値。

初期化リストを許可しながらデフォルトで初期化を作成することに関しては、基本タイプの初期化テンプレートを使用します。

template <typename T>
struct init
{
    init(): value_() {}
    template <typename S> init(S&& value): value_(std::forward<S>(value)) {}
    T value_;
};

struct foo
{
    init<int>    i_;
    init<double> d_;
    std::string  s_;
};

int main()
{
    foo f0;
    foo f1 = { 1, 3.14, "foo" };
    foo f2 = { };
}

このアプローチにより、クラスのオブジェクトの使用方法に関係なくメンバーが初期化されると同時に、初期化子リストの使用もサポートされます。ただし、gccは、誤って、初期化子の欠落について警告します。

于 2012-12-25T14:49:35.133 に答える