C++ 是否有一种情况下,包含相同的标题两次实际上是有帮助的?

C++ 是否有一种情况下,包含相同的标题两次实际上是有帮助的?,c++,c,C++,C,为我的h/hpp文件创建头保护一直是我的标准做法,但我想知道,为什么可能两次包含同一个文件?是否确实需要不受保护的标题?像Boost.PP这样的东西通过多次包含标题来实现很多技巧。它本质上允许循环的原始形式 此外,设计为多次包含。可以使用“参数化”头文件模拟C++中的C++-ish样式模板。在这种情况下,头文件将取决于多个宏(“模板参数”)。它将根据这些宏的实际“值”生成不同的代码 因此,此类标题的典型用法是一系列“模板参数”宏定义,后跟#include指令,再后跟另一系列“模板参数”宏定义,后

为我的h/hpp文件创建头保护一直是我的标准做法,但我想知道,为什么可能两次包含同一个文件?是否确实需要不受保护的标题?

像Boost.PP这样的东西通过多次包含标题来实现很多技巧。它本质上允许循环的原始形式

此外,设计为多次包含。可以使用“参数化”头文件模拟C++中的C++-ish样式模板。在这种情况下,头文件将取决于多个宏(“模板参数”)。它将根据这些宏的实际“值”生成不同的代码

因此,此类标题的典型用法是一系列“模板参数”宏定义,后跟
#include
指令,再后跟另一系列“模板参数”宏定义,后跟相同的
#include
,依此类推


使用此技术时,您将看到没有任何包含保护的头文件或包含保护的头文件仅覆盖文件的一部分。

类似的情况很少见,当确实存在时,重新设计更适合。我能想到的一个是聚集声明的标题:

//functions.h
virtual void foo();
virtual void goo();

//classes.h
class A : public Base
{
    #include "functions.h"
};

class B : public Base
{
    #include "functions.h"
};
如果
functions.h
包含了防护装置,这就不起作用了,但同样,这是一个相当笨拙的代码…

在C中:

#undef NDEBUG
#include <assert.h>

...code using active asserts...

#define NDEBUG
#include <assert.h>

...code using disabled asserts...
#未定义NDEBUG
#包括
…使用活动断言的代码。。。
#定义NDEBUG
#包括
…使用禁用断言的代码。。。
冲洗并重复。C++中的模拟使用标题<代码> <代码>。
因此,有时有理由包含两次标题。不经常,但这样做是有原因的。

头文件只是在遇到它们时以文本形式包含。没有任何真正的理由不能将它们包含多次。如果头只用于声明,而没有定义(也没有带有默认参数的模板声明),那么多次包含它们就不会有任何问题

也就是说,
是多次包含文件的典型示例:您可以更改
NDEBUG
的定义,并在一个翻译单元内从
assert()
宏获得不同的行为

现在像
include_once
这样只包含一次文件的东西并不像人们想象的那么简单。下面是一个例子,其中不清楚应该包括多少次
foo.h

#include_once "foo.h"
#include_once "./foo.h"
#include_once "bar/foo.h"

假设
include_once
只包含每个文件一次,那么应该多久包含一次
foo.h
?所有三个文件都可以很容易地引用同一个物理文件,但这可能不容易看到,例如,因为其中一个文件是指向另一个文件的链接。似乎最好将控制权交给程序员如何控制它们最终被使用的频率。

想象一下,您正在为您的微型引擎编写自己的模板数组包装器(元素是指针),其中数组可以是:

  • 动态还是静态
  • 索引/顺序是否重要
  • 可以在数组外部或内部删除元素(而不仅仅是从数组中删除)
因此,您可以创建一个类来处理所有这些,但它总是检查我们能做什么或不能做什么。最好是创建单独的类,但这里我们在它们之间有太多相同的代码,您可能(如果不小心的话)在其中一个函数中出错,再加上添加一个新函数会更慢

所以最好是使用“参数化”头文件(如AnT所述),并简单地创建如下类

  • Cl_数组_Dy,Cl_数组_DyIn,Cl_数组_DyDel,Cl_数组_DyInDel
  • Cl_数组St,Cl_数组StIn,Cl_数组StDel,Cl_数组StInDel
代码示例:

//TestDfM.h

#ifndef TEST_DFM_H
#   define TEST_DFM_H

    // first we need to make sure neither of these is defined
#   ifdef Df_ARG1
#       undef Df_ARG1
#   endif
#   ifdef Cl_First
#       undef Cl_First
#   endif
#   ifdef Cl_Second
#       undef Cl_Second
#   endif
#   ifdef Df_FIRST
#       undef Df_FIRST
#   endif
#   ifdef Df_SECOND
#       undef Df_SECOND
#   endif
#   ifdef TEST_DF_H
#       undef TEST_DF_H
#   endif

    // we need this
#   define Df_FIRST 1
#   define Df_SECOND 2

    // first class creation
#   define Df_CLASS Df_FIRST
#   define Df_ARRAY Cl_First
#   include "TestDf.h"

    // cleanup (after 1st)
#   undef Df_CLASS
#   undef Df_ARRAY

    // second class creation
#   define Df_CLASS Df_SECOND
#   define Df_ARRAY Cl_Second
#   define Df_ARG1
#   include "TestDf.h"

    // cleanup (after 2st)
#   undef Df_CLASS
#   undef Df_ARRAY
#   undef Df_ARG1

    // so we theoretically cannot include TestDf.h anymore (anywhere)
#   define TEST_DF_H

#endif // TEST_DFM_H
//TestDf.h

// nothing to do here if the main header for this was not included
// also we should only call this inside the main header
#if defined(TEST_DFM_H) && !defined(TEST_DF_H)
#   include "../Includes.h"

    class Df_ARRAY {
    public:
        int m_shared;

#   ifndef Df_ARG1
        Df_ARRAY(int in_shared=0) { m_shared= in_shared; }
        void f_info() { printf("out: %d\n", m_shared); }
#   else
        int m_x;
        Df_ARRAY(int in_shared=0, int in_x= 7) { m_shared= in_shared; m_x= in_x; }
        void f_info() { printf("out: %d [also has %d]\n", m_shared, m_x); }
#   endif

#   if Df_CLASS == Df_FIRST
        void f_class() { printf("1st\n"); }
#   elif Df_CLASS == Df_SECOND
        void f_class() { printf("2nd\n"); }
#   endif
    };

#endif // TEST_DFM_H
//Main.cpp

#include "Array/TestDfM.h"

int main(int argc, char** argv) {
    Cl_First a(6);
    Cl_Second b(2);
    a.f_class(); // 1st
    b.f_class(); // 2nd
    a.f_info(); // out: 6
    b.f_info(); // out: 2 [also has 7]
    return 0; }

由于某些标头包含其他标头,因此需要访问其中定义的类型。最初的C设计没有包含隐式的“保护”(大多数C编译器也没有添加)。在某些情况下,多次包含代码可能很有用,但这些都不是常规的“标题”。(Objective-C有
#import
指令,其他语言有
includeonce
或类似的指令,所以没有理由不这样做——C的开发人员根本就没有时间去做。)值得一提的是,原来的“汇编程序”之所以被称为“汇编”是指多个包含文件的程序,这种“闭合”子程序被认为是懦弱的。因此,<>代码>的概念包括< /代码>工作,它的方式与先前的实践一致,似乎是“自然的”。+1对于Wikipedia X-Macros链接(尽管常见问题解答对此表示不满)。其他语言很容易做到这一点,为什么c/c++也这么做会不那么简单?@Luke B:还有哪种语言使用文本包含(而不是某种midule系统)并解决了问题(可移植且正确)现在你只是移动门柱,在决定文件的整个路径之前,检查什么是如此困难?什么文本包含或不与它有关?@ Lukbb.:我没有移动任何目标帖子!我陈述了C和C++正在做什么和需要处理的问题,我真的不知道另一个系统完全相同,解决了这个问题。知道哪些文件只需要包含一次,哪些不需要。问题的一部分是相同的文件(或相同的内容)可以使用多个路径访问,取决于文件的包含方式,编译器会找到不同的实例,但它们都具有相同的内容。确定位置是不够的,也不能确定文件标识(如inode).Autohotkey有一个
#include
,它只包含一次文件。它还有一个
#includeAgain
,它强制另一次包含文件