place utility例程与它使用的类型在同一名称空间中?

时间:2017-02-21 20:25:30

标签: c++ namespaces

我有一堆我自己的对象,我尽职尽责地把它放在我自己的命名空间中:

namespace my { struct foo final {}; /* etc. */}

我应该把我的类型作为参数的非成员非朋友函数(即"全局"实用程序例程)放在哪里?我是否也应该将它们放在my命名空间

namespace my { extern void f(const foo&); }

或者,将它们放在全局命名空间中是否存在上行(或下行)

extern void f(const my::foo&);

在任何一种情况下,f的参数都是my::foo,那么函数本身是否实际命名为::f()my::f()是否重要?

编辑:请注意,我特别正在寻找"我喜欢全球"或者"我喜欢命名空间" (或类似的)。相反,我寻求特定的技术理由而不喜欢一种方法(假设实际存在这种差异)。从评论来看,这听起来像一个(?)因素可能是ADL行为;还有其他吗?

2 个答案:

答案 0 :(得分:1)

将操作紧密耦合到与该类型相同的命名空间中的类型允许Argument Dependent Lookup或Koenig查找工作。

污染全局命名空间通常是一个坏主意;你只获得一个全局命名空间,如果你的代码没有与其他人一起玩,那么解决方案很少。

例如,如果在全局命名空间中有一个名为CString的类型或函数,并且尝试包含并使用向全局命名空间注入CString的MFC代码,那么就会搞砸。 / p>

将代码放在namespace中意味着您使用一个标记污染全局命名空间,而不是每个函数和类型名称(等)一个。

要考虑的第二件事是,如果您的类型生成template,则在friend中放置template函数会导致ADL可发现的非template函数在与模板的类实例的实例交互时找到。

namespace my {
  template<class T>
  struct foo {
    friend foo operator+( foo lhs, foo rhs ) { return {lhs.x+rhs.x}; }
    friend foo add( foo lhs, foo rhs ) { return {lhs.x+rhs.x}; }
    int x;
  };
}

现在my::foo f0{0},f1{1}; auto f2 = add(f0, f1);auto f3=f0+f1;一样有用。

这里的addoperator+都不是模板,这意味着如果我们有一个转换为foo的类型,add(f0, converts_to_foo)也可以。

答案 1 :(得分:1)

这取决于。有时你有一个函数从不相关的命名空间中获取两个参数(例如在I / O或序列化中),它可以驻留在其中任何一个(但不在全局命名空间中!)

// foo can be either in N1 or N2, but not in global
namespace N1 { auto foo(A&, N2::B const&) }
namespace N2 { auto foo(N1::A&, B const&) } 

或者你有一个算法可以用于泛型参数(例如输入和输出范围),你可以将该函数放在自己的命名空间中

// algo should probably be in its own namespace N
namespace N {
    template<class R1, class R2>
    auto algo(R1 const& in, R2& out)
}

最好在不依赖ADL的情况下调用此类算法,即N::algo(rin, rout)