在我的代码库中,我在.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>
,它导致预处理器加载我的文件而不是标准库提供的文件。
答案 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
。)