1. ホーム
  2. c++

[解決済み] 委譲されたコンストラクタを使用したメンバ初期化

2022-11-04 22:40:53

質問

C++11 標準を試し始めたところ、以下のようなことがわかりました。 この の質問で、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()の部分をリストの最初と最後に移動してみましたが、それは役に立ちませんでした。

この背景にはどのような理由があり、どのように修正すればよいのでしょうか?私は lines(lines) をボディに移動してみました。 this->lines = lines; で代用するとうまくいきます。しかし、私は本当にイニシャライザーリストを使用できるようにしたいと思います。

どのように解決するのですか?

メンバの初期化を他のコンストラクタに委ねた場合、他のコンストラクタがオブジェクトを初期化することが前提になります。 完全に を初期化することが前提です。 lines メンバーも含む)。したがって、どのメンバーも再び初期化することはできません。

標準からの関連する引用は、(強調)です。

(§12.6.2/6) mem-initializer-list は、コンストラクタのクラス自身を示す任意の class-or-decltype を用いて、コンストラクタのクラスの他のコンストラクタに委譲することができる。mem-initializer-id がコンストラクタのクラスを指定する場合。 を指定する場合、それは唯一の mem-initializer で選択されたコンストラクタがターゲットコンストラクタである場合、そのコンストラクタは委譲コンストラクタとなります。[...]

引数を取るバージョンのコンストラクタを定義することで、これを回避することができます。 まず :

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

で、デリゲーションを使ってデフォルトのコンストラクタを定義します。

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

一般的なルールとして、コンストラクタのうち最も多くの引数を取るバージョンを完全に指定し、他のバージョンから委譲する必要があります(委譲の引数として希望のデフォルト値を使用します)。