我有一堆我自己的对象,这些对象已尽职尽责地放入自己的名称空间中:
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行为。还有其他吗?
将操作紧密耦合到与类型允许参数依赖查找或koenig查找的类型相同的类型。
污染全球名称空间通常是一个坏主意。您只会获得一个全局名称空间,如果您的代码不使用其他人放置的内容,则很少有解决方案。
例如,如果您在全局名称空间中具有名为CString
的类型或功能,并且尝试包括并使用MFC代码,将CString
注射到全局名称空间中,则将您拧紧。
将代码放在namespace
中表示您用一个令牌污染全局名称空间,而不是每个功能和键入名称(etc)。
要考虑的第二件事是,如果您的类型是template
生成的,则将friend
函数放置在template
中会导致可见的非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)
也可以工作。
它取决于。有时,您有一个函数,该函数从无关的名称空间(例如在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)
。