10

我知道为什么存在包含警卫,这#pragma once不是标准的,因此不受所有编译器等的支持。

我的问题是不同的:

有什么合理的理由永远没有它们吗?我还没有遇到过这样一种情况,理论上,不在文件中提供包含保护,该文件应该包含在其他地方。有没有人举个例子,没有它们有实际好处?

我问的原因 - 对我来说,它们似乎是多余的,因为你总是使用它们,而且 的行为#pragma once也可以自动应用于几乎所有的东西。

4

6 回答 6

11

我已经看到根据包含之前定义的宏生成代码的标头。在这种情况下,有时需要将这些宏定义为一个(一组)值,包含标题,重新定义宏,然后再次包含。
看到这种情况的每个人都同意它是丑陋的,最好避免,但有时(例如,如果所述标头中的代码是通过其他方式生成的)这样做的危害较小。

除此之外,我想不出理由。

于 2011-03-04T08:46:07.297 回答
6

@sbi 已经讨论过代码生成,所以让我举个例子。

假设您有很多项目的枚举,并且您想为其每个元素生成一堆函数......

一种解决方案是使用这种多重包含技巧。

// myenumeration.td
MY_ENUMERATION_META_FUNCTION(Item1)
MY_ENUMERATION_META_FUNCTION(Item2)
MY_ENUMERATION_META_FUNCTION(Item3)
MY_ENUMERATION_META_FUNCTION(Item4)
MY_ENUMERATION_META_FUNCTION(Item5)

然后人们就这样使用它:

#define MY_ENUMERATION_META_FUNCTION(Item_) \
  case Item_: return #Item_;

char const* print(MyEnum i)
{
  switch(i) {
    #include "myenumeration.td"
  }

  __unreachable__("print");
  return 0; // to shut up gcc
}

#undef MY_ENUMERATION_META_FUNCTION

这是好是坏取决于您,但显然每次向枚举添加新值时不必爬过所有实用程序函数是有用的。

于 2011-03-04T09:28:04.767 回答
4
<cassert>
<assert.h>

“每次包含 <assert.h> 时,都会根据 NDEBUG 的当前状态重新定义断言宏。”

于 2011-03-04T08:56:49.167 回答
0

如果您在一个项目中有两个使用相同包含保护的标头,则可能会出现问题,例如,如果您有两个第三方库,并且它们都有一个使用包含保护符号的标头,例如__CONSTANTS_H__,那么您将不会能够#include在给定的编译单元中成功地处理两个头文件。更好的解决方案是#pragma once,但一些较旧的编译器不支持此功能。

于 2011-03-04T08:49:03.147 回答
0

假设你有一个第三方库,你不能修改它的代码。现在假设包含该库中的文件会生成编译器警告。您通常希望在高警告级别编译您自己的代码,但这样做会因使用该库而产生大量警告。您可以编写警告禁用器/启用器标头,然后您可以将其包装在第三方库中,并且它们应该能够被包含多次。

另一种更复杂的使用是 Boost 的预处理器迭代构造: http: //www.boost.org/doc/libs/1_46_0/libs/preprocessor/doc/index.html

于 2011-03-04T08:52:14.767 回答
-1

#pragma once 的问题以及它不是标准的一部分的原因是它并不总是在任何地方都有效。如果两个文件来自不同的路径,编译器如何知道两个文件是否是同一个文件?

想一想,如果编译器出错,没有包含它应该包含的文件,会发生什么?如果它包含一个文件两次,它不应该有会发生什么?你会如何解决这个问题?

使用包含守卫,可能发生的最坏情况是编译需要更长的时间。

编辑:在 comp.std.c++ “#pragma once in ISO standard yet?”上查看这个线程?

http://groups.google.com/group/comp.std.c++/browse_thread/thread/c527240043c8df92

于 2011-03-04T17:47:33.970 回答