2

状況は次のとおりです。

次のファイルで定義されたクラスがあります。

Foo.h ファイル:

template<typename MyType>
class Foo
{
public:
    Foo(int number = 50);

private:
    typedef enum {VAR1, VAR2} Type;

    class Bar
    {
        MyType a;
        Type b;

        Bar(int param1, Type param2) : a(param1), b(param2) {}
    }

    std::vector<Bar> vec;
};

Foo.cpp ファイル:

template<typename MyType>
Foo::Foo(int number) : vec(number)
{ }

問題は、これをコンパイルすると、.cpp ファイルの最初の行に、引数のない Bar のコンストラクターが必要であるというエラーが表示されることです。Fooでベクトルを作成するために必要だと思います。次の .h ファイルを与える Bar の引数なしのコンストラクターを追加しました。

template<typename MyType>
class Foo
{
public:
    Foo(int number = 50);

private:
    typedef enum {VAR1, VAR2} Type;

    class Bar
    {
        MyType a;
        Type b;

        Bar() {}   // <----  Line added
        Bar(int param1, Type param2) : a(param1), b(param2) {}
    }

    std::vector<Bar> vec;
};

これでコンパイルできて動作しますが、追加したばかりの行にMember 'b' was no initialized in this constructor. enumに問題があるのでしょうか?

この警告なしで動作させるために何をすべきかわかりません。

編集:空のコンストラクターに初期化リストを追加するようにといういくつかの回答を受け取りました。しかし、私のクラスは実際にはテンプレートクラスでありa、私には不明な型であるため、型がわからないため初期化できません。Bar の初期化リストでのみ初期化を試みたところb、うまくいきました。aワーニングは消えましたが、未初期化のままでいいですか?Bar の引数なしでコンストラクターを削除し、それでも Foo のコンストラクターのベクトルにサイズを与える方法はありますか?

4

2 に答える 2

6

問題は、 の定義の初期化子リストですFoo::Foo(int)。あなたが書いている

Foo::Foo(int n)
    : vec(n) { }

つまり、コンストラクターを使用しています

std::vector<Bar>::vector(size_t number, const Bar &x = Bar())

x = Bar()これは、ベクトルを の標準構築インスタンスで埋めることを意味することに注意してくださいBar。コンパイラで少なくとも 1 つのコンストラクターが定義されBarているため、標準のコンストラクターは自動的に提供されません。

他の回答が提案するように標準コンストラクターを定義するBarか、のコンストラクターに何か他のものを入れます。Fooたとえば、これ

Foo::Foo(int n)
    : vec(n, Bar(1, VAR1)) { }

そしてコンパイラエラーは消えます。

あなたの編集への回答:あなたが受け取る警告はおそらく次のことを意味します:メンバーaが適切に初期化されていません。であるため、intこれで問題ない可能性があります (C++ ではints の初期化は強制されません)。aただし、プログラムの後半にあるメンバーの奇妙で恣意的な値に注意してください。より良い解決策は、構築時に「この値は不明」であることを意味する明確な状態に設定することです。

編集:異種コンテナについて書いたものをすべて削除しました。ただし、これらのものが必要な場合は、私の投稿の編集履歴をご覧ください。

次のようなa標準コンストラクターで初期化できます。Bar

Bar::Bar() : a(MyType()), b(UNKNOWN) { }

UNKNOWNおよび列挙に追加することによりTypeMyTypeこれは、型が標準の構築可能であることを前提としています。これは、たとえば 、 などのすべてのプリミティブ型に適用されintます。これにより、オブジェクトdoubleの明確に定義された状態が得られます。これは、不明を意味する可能性があります。と比較することでテストできます。BarbUNKNOWN

yakk が彼のコメントで述べたように: 列挙型のようなプリミティブ型は初期化されたままにすることができますが、あなたの場合、コンパイラは警告します: あなたのメンバーには、ラベルのようなまたはbまったくない値が含まれている可能性があります。すべてのメンバーを適切に定義された値で初期化することは常に良い考えです。たとえば、実行が非常に重要な場合など、そうしないと本当に強制されない限りです。VAR1VAR2

于 2013-03-24T10:04:05.627 に答える
0

空のコンストラクターに初期化リストを追加する必要があります (そしておそらく公開する必要があります)。

class Bar
{
    int a;
    Type b;

    Bar() : a(0), b(VAR1) {}   // initialize the members to default values.
    Bar(int param1, Type param2) : a(param1), b(param2) {}
}
于 2013-03-24T10:00:52.093 に答える