我有一堆我自己的对象,我尽职尽责地把它放在我自己的命名空间中:
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行为;还有其他吗?
答案 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;
一样有用。
这里的add
和operator+
都不是模板,这意味着如果我们有一个转换为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)
。