Хорошо, поэтому перед всеми вами 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 включать это или только пользовательские заголовки? Могут ли охранники помешать этому случиться?
Спасибо за вашу помощь, я действительно ценю это.