C ++: включить заголовки (неполный тип не допускается) - PullRequest
0 голосов
/ 06 февраля 2020

Хорошо, поэтому перед всеми вами go, указывающими мне на различные посты, где этот вопрос уже был рассмотрен, я хочу sh заявить, что я действительно решил свою проблему после этого поста здесь .

Этот пост больше о копании под поверхностью того, как работает компилятор.

Здесь мы go ...

Menu.h включает MenuEntry.h и MenuEntryKey.h, например, так:

#ifndef MENU_H
#define MENU_H

#include <cstdlib>
#include <map>
#include <string>

#include "MenuEntry.h"
#include "MenuEntryKey.h"

class Menu
{
public:
    // ctor, dtor, copy control
    Menu(const std::map<MenuEntryKey, MenuEntry> &opts = std::map<MenuEntryKey, MenuEntry>(),
         const unsigned numF = 0, const unsigned numD = 0) : options_(opts),
                                                             numFoodOptions_(numF),
                                                             numDrinkOptions_(numD) {}
    ~Menu() {}
    Menu(const Menu &);
    Menu &operator=(const Menu &);
    // entry select funcs: both simply return a random menu selection's name, based on the provided entry type.
    inline const std::string selectOption(const char);

private:
    const std::map<MenuEntryKey, MenuEntry> options_;
    const unsigned numFoodOptions_;
    const unsigned numDrinkOptions_;
    // private accessors; Guests must only be able to select a valid option. This can be changed later, if need be.
    inline const std::map<MenuEntryKey, MenuEntry> &getOptions() const { return options_; }
    inline const std::map<MenuEntryKey, MenuEntry> &getOptions()
    {
        return (static_cast<const Menu &>(*this)).getOptions();
    }
    inline const unsigned getNumFoodOptions() const { return numFoodOptions_; }
    inline const unsigned getNumDrinkOptions() const { return numDrinkOptions_; }
};

#endif // MENU_H

Показывать вам MenuEntry.h и MenuEntryKey.h действительно не имеет отношения к этому вопросу; оба они являются просто автономными компонентами, используемыми для создания меню.

Далее у меня есть класс DataLoader, который создает меню на основе метаданных открытого текста. Вот DataLoader.h:

#ifndef DATALOADER_H
#define DATALOADER_H

#include <iostream>
#include <fstream>
#include <map>
#include <vector>
#include <ctype.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

#include "Menu.h"
#include "MenuEntryKey.h"
#include "MenuEntry.h"

class Menu;

namespace DataLoader
{
const Menu &createMenu();
} // namespace DataLoader

#endif // DATALOADER_H

Как есть, в DataLoader.cpp нет ошибок; однако, как только я удаляю файлы MenuEntry.h и MenuEntryKey.h из DataLoader.h, вот так:

#ifndef DATALOADER_H
#define DATALOADER_H

#include <iostream>
#include <fstream>
#include <map>
#include <vector>
#include <ctype.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

#include "Menu.h"
// Note the missing includes that used to be here.
// "" ""

class Menu;

namespace DataLoader
{
const Menu &createMenu();
} // namespace DataLoader

#endif // DATALOADER_H

Я получаю , неполный тип не допускается (DataLoader. cpp):

#include "DataLoader.h"

const Menu &DataLoader::createMenu()
{
    std::ifstream in;
    in.open("../../../../meta/menu.md");

    if (!in)
    {
        std::cout << "Unable to open file.\n"; 
        exit(-1);
    }
    std::map<MenuEntryKey, MenuEntry> options;
    std::string line;
    while (std::getline(in, line))
    {
        if (line.size() == 0)
            continue; 

        if (line[0] == '-')
        {
            char entryType = toupper(line[1]);
            unsigned num = 0;
            std::vector<std::string> tokens;
            std::getline(in, line);

            while (line[0] != '^')
            {
                boost::algorithm::split(tokens, line, boost::algorithm::is_any_of(" "));

                MenuEntryKey key; //INCOMPLETE TYPE ERROR HERE
            }
        }
    } // end while
}

Причина, по которой меня это так озадачивает , заключается в том, что Menu.h включает в себя MenuEntry.h и MenuEntryKey.h! Не означает ли это, что включение Menu.h также включало бы последние два ? Пожалуйста, расскажите мне об этом странном происшествии.

Причина, по которой я не хочу включать MenuEntry.h и MenuEntryKey.h в DataLoader.h, заключается в том, что я узнал, что в целом рекомендуется избегать включения вещей, которые Я уже пытался получить лучшее управление.

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

Дайте мне знать, если вам нужна дополнительная информация. Надеюсь, этот вопрос подходит для SO, и я предоставил достаточно подробностей.

Cheers

EDIT:

Я вижу небольшую путаницу в комментариях, поэтому я Я постараюсь уточнить мой вопрос как можно лучше.

• Menu.h включает ОБА MenuEntry.h и MenuEntryKey.h.

• Только MenuEntry.h и MenuEntryKey.h включает в себя буквально ничего. AFAIK, циклических зависимостей между Menu.h, MenuEntry.h и MenuEntryKey.h нет.

• Когда DataLoader. cpp включает ТОЛЬКО Menu.h, препроцессор не может найти полное определение для MenuEntryKey. h ИЛИ MenuEntry.h, даже если оба эти файла включены в Menu.h.

Если включение работает аналогично копированию и вставке кода, то почему препроцессор не может найти полные определения для MenuEntry и MenuEntryKey в DataLoader. cpp? Не следует, включая Menu.h, скопировать и вставить код из этого заголовка, который, в свою очередь, копирует и вставляет заголовки MenuEntry.h и MenuEntryKey.h ???

Надеюсь, это поможет.

По запросу я приведу базовый c рабочий пример того, о чем я говорю. Пожалуйста, дайте мне 5 минут.

РЕДАКТИРОВАТЬ # 2 :

Вот ваш минимальный воспроизводимый пример.

MenuEntryKey.h:

#ifndef MENUENTRYKEY_H
#define MENUENTRYKEY_H

class MenuEntryKey
{
public:
    MenuEntryKey(char type = '!', unsigned num = 0) : type_(type), num_(num) {}

private:
    const char type_;
    const unsigned num_;
};

#endif // MENUENTRYKEY_H

MenuEntry.h:

#ifndef MENUENTRY_H
#define MENUENTRY_H

#include <string>

class MenuEntry
{
    const std::string name_;
};

#endif // MENUENTRY_H

Menu.h:

#ifndef MENU_H
#define MENU_H

#include "MenuEntry.h"
#include "MenuEntryKey.h"

class Menu
{
public:
private:
    const unsigned numFoodOptions_;
    const unsigned numDrinkOptions_;
};

#endif // MENU_H

DataLoader.h:

#ifndef DATALOADER_H
#define DATALOADER_H

class Menu;

namespace DataLoader
{
const Menu &createMenu();
} // namespace DataLoader

#endif // DATALOADER_H

DataLoader. cpp:

#include "DataLoader.h"
#include "Menu.h"
// #include "MenuEntry.h"
// #include "MenuEntryKey.h"

const Menu &DataLoader::createMenu()
{
    MenuEntryKey key;
}

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

Почему это сработало бы сейчас, а раньше - нет? Это должно иметь отношение к включенным заголовкам; Может ли заголовок STL включать это или только пользовательские заголовки? Могут ли охранники помешать этому случиться?

Спасибо за вашу помощь, я действительно ценю это.

...