Подтвердить что ты не робот

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

Я начал пробовать стандарт С++ 11 и нашел этот вопрос, который описывает, как вызывать ваш ctor из другого ctor в том же классе, чтобы избежать использования метода init или чего-либо подобного. Теперь я пытаюсь сделать то же самое с кодом, который выглядит следующим образом:

HPP:

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

каст:

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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