Определение функции участника-члена конфликтует с инициализатором в классе

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

В самом начале код работал нормально, когда я не добавлял функцию члена-друга.

/* First class */
class Screen {
public:
    using pos = std::string::size_type;
    using content_type = char;

    Screen() = default;
    Screen(pos ht, pos wd, content_type c)
        : height(ht), width(wd), contents(ht * wd, c) {}

    // Other inline functions are omited.

private:
    pos width = 0;
    pos height = 0;
    std::string contents;
};

/* Second class */
class Window_mgr {
public:
    using screen_index = std::vector<Screen>::size_type;

private:
    std::vector<Screen> screens{Screen(24, 80, ' ')};  // Use `Screen` ctor
};

Затем я хочу добавить функцию члена-друга clear. Я написал две версии кода в соответствии с кодом около страницы 281 в книге. Первая версия использует инициализатор в классе для инициализации элемента данных vector Window_mgr, а вторая версия использует список инициализаторов конструктора.

Первая версия (ошибка), как и то, что написала книга:

Создание функции-члена для друга требует тщательной структуризации наших программ для учета взаимозависимостей между декларациями и определениями. В этом примере мы должны заказать нашу программу следующим образом:

  • Сначала определите класс Window_mgr, который объявляет, но не может определить clear. Screen должен быть объявлен до того, как clear может использовать члены Screen.
  • Затем определите класс Screen, включая объявление друга для clear.
  • Наконец, определите clear, который теперь может ссылаться на члены в Screen.
/* Part 1, usually Window_mgr.h */
class Screen;

class Window_mgr {
public:
    using screen_index = std::vector<Screen>::size_type;
    void clear(screen_index);

private:
    std::vector<Screen> screens{Screen(24, 80, ' ')};  // Error: No ctor for `Screen`
};

/* Part 2, usually Screen.h */
class Screen {
    friend void Window_mgr::clear(screen_index);

public:
    using pos = std::string::size_type;
    using content_type = char;

    Screen() = default;
    Screen(pos ht, pos wd, content_type c)
        : height(ht), width(wd), contents(ht * wd, c) {}

    // Other inline functions are omited.

private:
    pos width = 0;
    pos height = 0;
    std::string contents;
};

/* Part 3, usually Window_mgr.cpp */
void Window_mgr::clear(screen_index i) {
    Screen &s = screens[i];
    s.contents = std::string(s.height * s.width, ' ');
}

Вторая версия (без ошибок), которая вдохновлена ​​этим ответом:

/* Part 1, usually Window_mgr.h */
class Screen;

class Window_mgr {
public:
    using screen_index = std::vector<Screen>::size_type;
    void clear(screen_index);
    Window_mgr();  // Add ctor declaration

private:
    std::vector<Screen> screens;  // Remove in-class initializer
};

/* Part 2, usually Screen.h */
class Screen {
    friend void Window_mgr::clear(screen_index);

public:
    using pos = std::string::size_type;
    using content_type = char;

    Screen() = default;
    Screen(pos ht, pos wd, content_type c)
        : height(ht), width(wd), contents(ht * wd, c) {}

    // Other inline functions are omited.

private:
    pos width = 0;
    pos height = 0;
    std::string contents;
};

/* Part 3, usually Window_mgr.cpp */
Window_mgr::Window_mgr() : screens{Screen(24, 80, ' ')} {}  // Add ctor definition
// Because `Screen` is already a complete type, we can use its ctor now

void Window_mgr::clear(screen_index i) {
    Screen &s = screens[i];
    s.contents = std::string(s.height * s.width, ' ');
}

Обратите внимание, что я поместил все 3 части кода в один файл для удобства, их также можно разделить на три разных файла с надлежащим включением охранников и включить файлы заголовков.

Я понимаю форвардную декларацию и включаю охранников, поэтому я не спрашиваю о них, вот мои вопросы.

  • Является ли конструктором вне класса Window_mgr единственным способом инициализировать элемент данных screens, если я хочу использовать класс Screen напрямую (не указатель или ссылку)?

    Я думаю, что инициализатор в классе нельзя использовать в первой версии, потому что Screen является неполным типом при вызове его ctor.

  • Почему неполный тип (Screen) можно использовать в качестве параметра для шаблона vector?

Возможные похожие вопросы:

Я старался быть ясно, но, похоже, немного подробный, в любом случае спасибо за чтение и помощь:)