web-dev-qa-db-ja.com

委任されたコンストラクターの使用中のメンバーの初期化

私はC++ 11標準を試し始めましたが、 this initメソッドなどを避けるために同じクラスの別のctorからあなたのctorを呼び出す方法を説明する質問を見つけました。今、私はこのようなコードで同じことを試みています:

hpp:

_class Tokenizer
{
public:
  Tokenizer();
  Tokenizer(std::stringstream *lines);
  virtual ~Tokenizer() {};
private:
  std::stringstream *lines;
};
_

cpp:

_Tokenizer::Tokenizer()
  : expected('=')
{
}

Tokenizer::Tokenizer(std::stringstream *lines)
  : Tokenizer(),
    lines(lines)
{
}
_

しかし、これは私にエラーを与えています:In constructor ‘config::Tokenizer::Tokenizer(std::stringstream*)’: /path/Tokenizer.cpp:14:20: error: mem-initializer for ‘config::Tokenizer::lines’ follows constructor delegationリストの最初と最後にTokenizer()部分を移動しようとしましたが、助けにはなりませんでした。

この背後にある理由は何ですか?どのように修正する必要がありますか?代わりに_this->lines = lines;_を使用してlines(lines)を本体に移動しようとしましたが、正常に動作します。しかし、私は本当に初期化子リストを使用できるようにしたいと思います。

前もって感謝します!

85
lfxgroove

メンバーの初期化を別のコンストラクターに委任すると、他のコンストラクターがオブジェクトを初期化するという前提がありますcompletely(すべてのメンバーを含む(例ではlinesメンバーを含む)。したがって、メンバーを再度初期化することはできません。

標準からの関連する引用は(強調鉱山)です:

(§12.6.2/ 6)mem-initializer-listは、コンストラクターのクラス自体を示すclass-or-decltypeを使用して、コンストラクターのクラスの別のコンストラクターに委任できます。 mem-initializer-idがコンストラクターのクラスを指定する場合、唯一のmem-initializer;コンストラクターは委任コンストラクターであり、によって選択されたコンストラクターはターゲットコンストラクターです。 [...]

これを回避するには、引数を取るコンストラクタのバージョンを定義しますfirst

Tokenizer::Tokenizer(std::stringstream *lines)
  : lines(lines)
{
}

次に、委任を使用してデフォルトのコンストラクタを定義します。

Tokenizer::Tokenizer()
  : Tokenizer(nullptr)
{
}

一般的な規則として、引数の最大数をとるコンストラクターのバージョンを完全に指定し、他のバージョンから委任します(委任で引数として目的のデフォルト値を使用)。

104
jogojapan