未命名的命名空间链接是内部的还是外部的,还是混合的?
在C++03标准中,有一种边缘情况下,static关键字会产生令人惊讶的效果。具体来说,在使用模板参数的函数调用中,如果函数名是一个未限定的标识符(unqualified-id),但不是一个模板标识符(template-id),则候选函数的查找规则会有所不同。根据14.6.4.2/1节中的规定:
- 对于使用未限定名称查找的部分(unqualified name lookup),只有来自模板定义上下文的具有外部链接的函数声明才会被找到。
- 对于使用相关命名空间查找的部分(associated namespaces),只有来自模板定义上下文或模板实例化上下文的具有外部链接的函数声明才会被找到。
这导致了下面的代码会调用`foo(void*)`而不是`foo(S const&)`,这可能与预期不符。
templateint b1 (T const& t) { foo(t); } namespace NS { namespace { struct S { operator void* () const; }; void foo (void*); static void foo (S const&); // 不被考虑在14.6.4.2(b1)中 } } void b2() { NS::S s; b1 (s); }
这个问题本身可能并不是很大的问题,但它确实凸显了对于一个完全符合C++标准(即支持`export`关键字)的编译器来说,`static`关键字仍然具有其他方式无法实现的功能。
在C++11标准中,匿名命名空间的成员具有隐式的内部链接(internal linkage)(3.5/4)。但与此同时,14.6.4.2/1节进行了更新,删除了关于链接(linkage)的提及(以下摘自C++14):
- 对于后缀表达式为依赖名(dependent name)的函数调用,候选函数的查找规则与通常的查找规则(3.4.1, 3.4.2)相同,只是:
- 对于使用未限定名称查找的部分(unqualified name lookup),只有来自模板定义上下文的函数声明会被找到。
- 对于使用相关命名空间查找的部分(associated namespaces),只有来自模板定义上下文或模板实例化上下文的函数声明会被找到。
结果是,static和匿名命名空间成员之间的这种特定差异不再存在。
“export”关键字是否已经过时了?支持“export”关键字的编译器只是实验性的,除非意外情况,否则其他编译器不会实现它,因为它会产生意想不到的副作用(除了没有按预期进行操作)。EDG(Edison Design Group)的前端编译器绝对不是实验性的,它几乎可以说是世界上符合C++标准最完善的实现。Intel C++编译器使用的就是EDG。
在C++中,哪个特性没有“意想不到的副作用”?对于“export”来说,它的副作用是,一个匿名命名空间函数会在不同的TU中被找到,这与直接包含模板定义是相同的。如果它不是这样,那才更令人惊讶!
我认为你有一个笔误——为了使`NS::S`工作,`S`不需要在`namespace {}`中吗?
`S`在匿名命名空间中声明,因此可以通过`NS::S`找到它。如果你感兴趣的话,N4687中的10.3.1.1描述了匿名命名空间的语义,6.4.3.2/2描述了限定名称的查找。
匿名命名空间(unnamed namespace)可以防止无意中违反《一次定义规则》(One Definition Rule),从而无需担心将辅助方法命名与其他链接的方法相同。此外,正如luke所指出的那样,标准更倾向于使用匿名命名空间而不是静态成员。
这里提到的是静态独立函数(即文件范围的函数),而不是静态成员函数。静态独立函数与匿名命名空间中的函数非常相似,因此产生了这个问题。
哦,好吧,仍然适用《一次定义规则》。编辑以删除该段落。
根据我的理解,当静态函数在头文件中定义,并且该头文件被包含到多个翻译单元中时,静态函数的《一次定义规则》不适用,对吗?在这种情况下,您会得到多个相同函数的副本。
T: 在包含的头文件中,您实际上并不会看到“多个定义”。预处理器会处理它。除非有必要研究预处理器生成的输出,这对我来说看起来相当奇特和罕见。此外,在头文件中包含“guards”的做法是很好的实践,例如:“#ifndef SOME_GUARD - #define SOME_GUARD ...”,这样可以防止预处理器重复包含同一个头文件。
该保护措施可能会防止将同一个头文件包含到同一个翻译单元中,但它允许在不同的翻译单元中进行多次定义。这可能会导致“多个定义”链接错误。
无名命名空间的链接是内部的、外部的还是混合的?
该问题的出现原因是在C++标准中,对于无名命名空间的链接性没有明确的规定,导致不同的解释和理解。有部分人认为无名命名空间的链接是内部的,有部分人认为是外部的。这种不一致的解释导致了对于无名命名空间链接性的混淆和争议。
然而,根据C++标准的规定,在C++11及以后的版本中,无名命名空间的链接性是内部的。这意味着无名命名空间中的声明只能在同一个翻译单元中访问,而不能在其他翻译单元中访问。
对于这个问题的解决方法是,在使用无名命名空间时,要根据C++标准的规定,将链接性视为内部的。这样可以确保无名命名空间中的声明只能在同一个翻译单元中访问。另外,也要注意在使用无名命名空间时,要将代码放在正确的位置,以确保其可见性和正确性。
总结起来,无名命名空间的链接性是内部的,这是根据C++标准的规定来确定的。在使用无名命名空间时,应该将其链接性视为内部的,以确保其声明只能在同一个翻译单元中访问。这样可以避免不同解释和理解对于无名命名空间链接性的混淆和争议。