简介:这样做是否安全
namespace Foo {
#include "bar"
}
在你轻率地说不之前,我想我有一些规则可以相当安全地允许它。
但我不喜欢它们,因为它们要求包含器单独包含所需的所有全局范围标头。尽管这可能是可以容忍的,但如果我们想象在命名空间中包含只是一个特殊的管理功能。
总的来说,外部和前向声明在命名空间内不能很好地工作。
所以我想我在问
a) 还有什么其他问题
b) 有没有更好的方法
== A [[仅标题库]] ==
我喜欢写图书馆。[[仅头文件库和链接器库]]。
例如
#include "Valid.hpp"
为简单的包装器类型定义了一个有效的模板。
(不要陷入“你应该为此使用一些标准库而不是你自己的库。这是一个例子。我不知道 Boost 或 C++ 是否已经标准化了这个。自从模板被添加到 C++ 以来,我一直在使用包装器。 )
另外,让我们说,它是一个只有头文件的库,它在 Valid.hpp 中定义了一个打印函数
std::string to_string( const Valid& v ) { std::ostringstream oss; if( v.valid() ) { oss << v; } 其他 {“无效”;} 返回 oss.str(); }
而且因为我认为这是正确的做法,所以我让 Valid.hpp 包含它所依赖的标头:
Valid.hpp:
#include <iostream>
#include <sstream>
template<typename T>
class Valid {
private:
T value_;
bool valid_
...
};
...
std::string to_string( const Valid<T>& v ) { ...
到目前为止,一切都很好。
我可以直接使用Valid。
== 名称冲突 - 尝试在命名空间中使用 include 来解决 ==
但有时也会发生碰撞。有时其他人有自己的Valid。
命名空间来拯救,对吧?但我不想更改所有现有代码以使用命名空间。所以,我很想,在一个有冲突的新项目中,做
namespace AG {
namespace Wrapper {
#include "lib/AG/Wrapper/Valid.hpp"
}
}
AG::Wrapper::Valid<T> foo_v;
...
问题:包含的标题不再是独立的。里面定义的所有东西都没有放在命名空间 AG::Wrapper 中。
“修复”并不难。
我们“必须”做的就是包含 Valid.hpp 所依赖的所有顶级库。如果他们有包含警卫,他们将不会被重新包含。
#include <iostream>
#include <sstream>
namespace AG {
namespace Wrapper {
#include "lib/AG/Wrapper/Valid.hpp"
}
}
AG::Wrapper::Valid<T> foo_v;
...
但它不再是独立的。:-(
更糟糕的是,有时只有标头的库包含外部声明和前向声明,它们在其外部。这些声明也被放置在命名空间内。特别是,如果 extern 声明位于命名空间中定义的函数内部。
即有时我们使用外部和前向声明,而不是包含整个头文件。这些被包含在命名空间中。
问:有没有更好的方法?
== :: 不这样做 ==
提示::: 不这样做。至少不是一直,不是在 gcc 4.7.2 中。
(Gcc 在这方面的行为随着时间的推移而改变。Gcc 4.1.2 的行为有所不同。)
例如
Type var;
namespace Foo {
void bar() {
extern ::Type ::var;;
extern ::Type ::Foo::bar;
extern ::Type::foo ::bar; // see the ambiguity?
};
但这不仅仅是模棱两可。
整数变量;
namespace Foo {
void bar() {
extern int var;
};
有效 - Foo::bar'svar 等于 ::var。
但它只是因为命名空间之外的声明才有效。
以下不起作用
标头 int var; cpp namespace Foo { void bar() { extern int var; } }
虽然以下是:
标头 int var; cpp void bar() { extern int var; } }
基本上,这等于说,将函数放在命名空间中并不是一项微不足道的重构。将命名空间包裹在一块代码周围,无论它是否是#include'd,都是不够的。...至少在有外部或前向声明的情况下不会。
而且即使你
== 反对将包含放入命名空间的意见 ==
Stackoverflow 的人似乎反对将#includes 放在命名空间中:
...您永远不应该在命名空间内编写#include。“从不”的意思是,“除非你正在做一些我没有想到的非常晦涩的事情并且证明它是合理的”。您希望能够查看文件,并查看其中所有内容的完全限定名称。如果有人稍后出现并通过在其命名空间中包含一个额外的命名空间,您将无法这样做。——史蒂夫·杰索普 2012 年 1 月 6 日 16:38
总体问题:
有没有办法从命名空间的深处说“现在这里有一些我依赖于外部世界的名称,而不是在命名空间内。”?
即我想说
namespace A {
void foo() {
// --- here is a reference to gloal scope extreren ...