C++ C++;:包含标题(不允许类型不完整)

C++ C++;:包含标题(不允许类型不完整),c++,include,C++,Include,好的,在你们把我引向不同的帖子之前,这个问题已经被解决了,我想声明,在这篇帖子之后,我确实解决了我的问题 这篇文章更多的是关于如何挖掘编译器工作的表面之下 我们走吧 Menu.h包括MenuEntry.h和MenuEntryKey.h,如下所示: #ifndef MENU_H #define MENU_H #include <cstdlib> #include <map> #include <string> #include "MenuEntry.h" #

好的,在你们把我引向不同的帖子之前,这个问题已经被解决了,我想声明,在这篇帖子之后,我确实解决了我的问题

这篇文章更多的是关于如何挖掘编译器工作的表面之下

我们走吧

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
#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
Menuntry.h:

#ifndef MENUENTRY_H
#define MENUENTRY_H

#include <string>

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

#endif // MENUENTRY_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"
#include "MenuEntryKey.h"
#include "MenuEntry.h"

class Menu;

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

#endif // 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"

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
}
#include "DataLoader.h"
#include "Menu.h"
// #include "MenuEntry.h"
// #include "MenuEntryKey.h"

const Menu &DataLoader::createMenu()
{
    MenuEntryKey key;
}
令人惊讶的是,这个框架示例没有产生不完整的类型错误。注意,这两个include语句被注释掉了

为什么现在这样做有效,而以前没有?它必须与包含的标题有关;STL标头包含是否会导致此问题,或者仅包含用户定义的标头?会有警卫阻止这种事情发生吗


感谢您的帮助,我真的很感激。

与编译器的工作方式相比,包含内容的工作方式更像是预处理器如何工作的问题。编译器根本不处理
#include
。在将结果传递给编译器之前,所有这些都由预处理器处理。记住C++编译是在不同的阶段完成的;首先进行预处理,然后进行编译(编译本身包括几个阶段:解析、优化、代码生成),然后汇编器生成一个目标文件,链接器然后将目标文件合并到库或可执行文件中只需要声明
菜单
。当需要执行时,所有的
#include
都应该放在cpp中。@如果您重视快速编译项目,请尝试减少标题中的include。如果可能,首选转发声明,并且只在源文件中包含完整的头。有时,您必须在标题中包含完整的标题/类型定义,但在绝对需要时继续这样做。就像您永远不应该将
using namespace…
放在头中一样,因为它会污染头的所有用户,头中不必要的包含会导致该头的所有用户中不必要的包含。在一个大型项目中,这可能意味着编译时间的巨大放缓。
#include
主要是复制粘贴文件内容。对于include-guard(很好)和循环依赖(必须避免),include的顺序很重要。(>表示
#此处包含
)带有menu.h->menu.h(->menu.h)由于包含保护而被丢弃,但从menu.h的角度来看,却丢失了。而menu.h->menu.h->(->menu.h)被丢弃[…])在其他方面存在问题。请提供一个,删除任何不相关的代码并提供所有代码,我无法用给定的代码重现此问题:。我怀疑在您的某个标头中包含防护将是重复的。
#ifndef DATALOADER_H
#define DATALOADER_H

class Menu;

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

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

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