一段困扰我一段时间的事情:
目前的看法是,类型应该只保留在命名空间中 包含属于该类型的非成员接口的函数(参见 C ++编码标准 Sutter和Alexandrescu或here),以防止ADL引入不相关的定义。
这是否意味着所有类必须拥有自己的命名空间?如果 我们假设一个类可以在将来通过添加来扩充 非成员函数,然后将两种类型放入其中是绝对不安全的 与其中任何一个相同的命名空间可能会引入非成员函数 这可能会干扰另一方。
我问的原因是命名空间对我来说变得很麻烦。我 编写一个只有头文件库,我发现自己使用类名,如 项目::组件:: CLASS_NAME :: CLASS_NAME。他们的实现调用 辅助函数,但因为它们不能在同一名称空间中 完全合格!
修改
有几个答案表明C ++命名空间只是一种避免名称冲突的机制。事实并非如此。在C ++中,使用Argument Dependent Lookup解析获取参数的函数。这意味着当编译器试图找到与函数名称匹配的函数定义时,它将在查找候选项时查看与其参数类型相同的名称空间中的每个函数
这可能会产生意想不到的令人不快的后果,详见A Modest Proposal: Fixing ADL。 Sutter和Alexandrescu的规则状态从不将函数放在与类相同的命名空间中,除非它是该类的接口的一部分。我不知道如何遵守这条规则,除非我准备给每个班级都有自己的命名空间。
非常欢迎更多建议!
答案 0 :(得分:15)
没有。我从来没有听说过这个惯例。通常每个库都有自己的命名空间,如果该库有多个不同的模块(例如功能不同的不同逻辑单元),那么可能有自己的命名空间,尽管每个库有一个命名空间就足够了。在库或模块命名空间内,您可以使用命名空间detail
或匿名命名空间来存储实现详细信息。每个类使用一个命名空间,恕我直言,完全矫枉过正。我肯定会回避这一点。同时,我强烈建议您至少为您的库创建一个名称空间,并将所有名称空间或其子名称空间放在其中,以避免与其他库发生名称冲突。
为了使其更具体,请允许我使用古老的Boost C++ Libraries作为示例。 boost中的所有元素都位于boost::
中。 Boost中有一些模块,例如具有自己的命名空间的进程间库,例如boost::interprocess::
,但在大多数情况下,boost的元素(特别是那些经常使用和跨模块的元素)只存在于{{1 }}。如果你在boost中查看,它经常使用boost::
或boost::detail
来存储给定命名空间的实现细节。我建议你以这种方式为你的命名空间建模。
答案 1 :(得分:8)
不,不,千次不! C ++中的命名空间不是架构或设计元素。它们只是一种防止名称冲突的机制。如果在实践中您没有名称冲突,则不需要名称空间。
答案 2 :(得分:7)
要避免ADL,您只需要两个名称空间:一个包含所有类,另一个包含所有松散功能。 ADL绝对不是每个类都有自己的命名空间的好理由。
现在,如果您希望通过ADL找到某些函数,则可能需要为此目的创建名称空间。但是,为了避免ADL冲突,你实际上每个类实际上还不太可能需要一个单独的命名空间。
答案 3 :(得分:0)
可能不是。请参阅Eric Lippert's post on the subject。
在这里结识:
您可以使用typedef
来节省一些typedef痛苦,但这当然只是一个创可贴。
答案 4 :(得分:0)
这是一篇非常有趣的论文,但随后给作者提供了很好的机会。但是,我注意到问题主要涉及:
typedef
,因为它们只引入别名而不是新类型如果我这样做:
namespace foo
{
class Bar;
void copy(const Bar&, Bar&, std::string);
}
并调用它:
#include <algorithms>
#include "foo/bar.h"
int main(int argc, char* argv[])
{
Bar source; Bar dest;
std::string parameter;
copy(source, dest, parameter);
}
然后它应该选择foo::copy
。事实上,它会考虑foo::copy
和std::copy
,但foo::copy
不是模板将优先考虑。