头文件名是否符合bits / vector.tcc标准?

时间:2014-06-16 09:05:55

标签: c++ language-lawyer

在我的代码库中,我在.tcc子目录中的bits文件中“隐藏”重度模板化代码的实现细节,即

// file inc/foo.h:
#ifndef my_foo_h          // include guard
#define my_foo_h
namespace my {
  /* ... */               // templated code available for user
}
#include "bits/foo.tcc"   // includes implementation details
namespace my {
  /* ... */               // more templated code using details from foo.tcc
}
#endif

// file inc/bits/foo.tcc:
#ifndef my_foo_tcc        // include guard
#define my_foo_tcc
#ifndef my_foo_h
#  error foo.tcc must be #included from foo.h
#endif
namespace my { namespace details {
  /* ... */               // defails needed in foo.h
} }
#endif

当然,include路径中只能有一个文件bits/foo.tcc。否则,将发生冲突并(希望)出现编译错误。这件事恰好发生在bits/vector.tcc上,它包含在gcc(4.8)vector中,但也包含在我自己的标题中(使用#include "bits/vector.tcc"而不是#include <bits/vector.h>)。

我的问题:这是gcc的正式错误(因为它使用的名称bits/vector.tcc不受标准保护)或正确,即使是正式的我的错?如果是后者,保证头文件的名称可以使用吗?

(注意我不想听到关于如何避免这种情况的明显建议。)


编辑问题是标准库(由编译器提供)提供的头文件vector有一个预处理器指令#include <bits/vector.tcc>,它导致预处理器加载我的文件而不是标准库提供的文件。

2 个答案:

答案 0 :(得分:2)

这是C ++ 11标准[cpp.include]对此有何看法:

  

1 #include指令应标识可由实现处理的标头或源文件。

     

2

形式的预处理指令
# include < h-char-sequence> new-line
     

在实现定义的位置序列中搜索由指定序列唯一标识的标头   在<>分隔符之间,并导致整个内容替换该指令   标题。如何指定场所或标识的标题是实现定义的。

     

3

形式的预处理指令
# include " q-char-sequence" new-line
     

导致由指定标识的源文件的全部内容替换该指令   "分隔符之间的序列。在实现定义中搜索指定的源文件   方式。如果不支持此搜索,或者搜索失败,则会重新处理该指令,就好像它已读取

一样
# include < h-char-sequence> new-line
     

使用相同的包含序列(包括>个字符,如果有的话)来自原始指令。

换句话说,#include < >仅用于搜索标题标头是标准库提供的功能之一。我说&#34;事情&#34;因为标准没有指定它是什么 - 它根本不需要文件(尽管我知道所有编译器都将头文件作为文件)。

#include " "适用于&#34;其他所有内容&#34; - 就标准而言,他们是所有源文件,&#34;虽然在一般性演讲中我们通常将用于#include d的文件称为&#34;头文件。&#34;另请注意,如果未找到此类源文件,则会搜索(标准库)标头。

所以,在你的情况下:

  • 标准对bits/vector.tcc等文件没有任何说明;事实上,它并没有说明任何文件。所有这些都属于&#34;实现定义的&#34;标题因此取决于您的编译器及其文档。

    同时(感谢@JamesKanze在评论中指出这一点),该标准明确规定了#include <vector>应该做什么,并且从未提及它可能取决于文件的存在或者缺席。所以在这方面,gcc加载你的bits/vector.tcc而不是它自己的是一个gcc bug。如果gcc加载了自己的bits/vector.tcc而不是你的,那么它将在其实现定义的#34;范围。

  • #include "vector"主要用于包含名为vector的源文件。但是,如果找不到此类文件,则效果与包含标准标题<vector>(导致类模板std::vector被视为已定义)相同。

答案 1 :(得分:0)

该标准相当开放,但......包括<vector>应该 工作;我没有看到任何授权它的东西(提供 您已完成#include <vector>,而不是#include "vector"), 无论您的个人姓名如何。

更一般地说,或多或少的通用算法 搜索标题是首先在目录中搜索哪个 包含包含的文件。这个完成了 正是为了避免您遇到的问题类型。 不这样做(或不使用其他一些机制来确保这一点 包括标准标题,找到他们应该的文件 to)是编译器中的错误。一个严肃的,恕我直言。 (的 当然,编译器可能会记录某些选项的引入 某些限制,或者您需要使用某些选项 因为它以标准方式表现。我不认为那是g ++ 文档-I与标准标题不兼容, 但它确实说如果你使用-iquote,它就不应该 影响使用<...>包含的任何内容。)

编辑:

上面第二段真的只适用于"..." 包括的形式。 #include <vector>应该找到 标准标题,即使您有相同的文件vector 目录作为您正在编译的文件。

-I选项缺席的情况下,这有效。通用, 但是,-I选项会在搜索列表中添加目录 对于两种类型的包含。原因是你, 作为开发者,可能会想要对待各种第三方 库(例如X-Windows)就好像它们是系统的一部分一样 好。 (我认为Linux确实将X-Windows作为系统的一部分, 将标题放在/usr/include中,但这不是通常的 过去其他Unices的案例。)所以你使用-I来指定 他们,以及你其他包括目录。如果你 在其他一个目录中有一个文件vector,它会 &#34;倍率&#34;系统一。

这显然是一个缺陷:如果我没记错的话(但事情已经过去了) 一段时间),g ++曾经有其他选择 列表中的目录只有一种类型的包含。并在 现代gcc / g ++,有-iquote(和-I-,它指定 所有早期-I选项都适用于"..." 仅包括)。但是,这些功能很少使用, 因为gcc / g ++是唯一支持它们的编译器。

鉴于这一切,gcc / g ++处理可能是你最好的 可以希望。错误不在编译器本身,但是 库标题,使用<bits/vector.tcc>时 绝对希望与同一目录中的包含文件 文件做包含。 (另一种说法是这样的 在任何意义上,bits/vector.tcc都不是系统标题 单词,但系统库的实现标题。)

除非他感觉到,否则这些都不能帮助原始海报 比如修改g ++的库头文件。 (如果可移植性 没有任何问题,他也没有考虑将他的标题作为其中的一部分 在系统中,他可以将-I更改为-iquote。)