Инициализация члена при использовании делегированного конструктора

98

Я начал пробовать стандарт C ++ 11 и нашел этот вопрос, который описывает, как вызвать ваш 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;вместо этого, и он отлично работает. Но я бы очень хотел иметь возможность использовать список инициализаторов.

lfx Groove
источник

Ответы:

120

При делегировании инициализации члена к другому конструктору, есть предположение , что другой конструктор инициализирует объект полностью , включая все член (т.е. включая linesчлен в вашем примере). Поэтому вы не можете снова инициализировать ни один из членов.

Соответствующая цитата из Стандарта (выделено мной):

(§12.6.2 / 6) Список-инициализатора памяти может делегировать другому конструктору класса конструктора, используя любой тип class-or-decltype, который обозначает сам класс конструктора. Если mem-initializer-id обозначает класс конструктора, он должен быть единственным mem-инициализатором ; конструктор является конструктором-делегатом, а конструктор, выбранный с помощью, является целевым конструктором. [...]

Вы можете обойти это, определив версию конструктора, который сначала принимает аргументы :

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

а затем определите конструктор по умолчанию, используя делегирование:

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

Как правило, вы должны полностью указать ту версию конструктора, которая принимает наибольшее количество аргументов, а затем делегировать из других версий (используя желаемые значения по умолчанию в качестве аргументов в делегировании).

Jogojapan
источник
2
Сначала это кажется нелогичным, но на самом деле действительно помогает!
Корчкиду