在一种边缘情况下,静电会产生令人惊讶的效果(至少对我来说是这样)。c++ 03标准在14.6.4.2/1中声明:
For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:
For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external linkage from the template definition context are found.
For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage found in either the template definition context or the template instantiation context are found.
...
下面的代码将调用foo(void*),而不是你可能期望的foo(S const &)。
template <typename T>
int b1 (T const & t)
{
foo(t);
}
namespace NS
{
namespace
{
struct S
{
public:
operator void * () const;
};
void foo (void*);
static void foo (S const &); // Not considered 14.6.4.2(b1)
}
}
void b2()
{
NS::S s;
b1 (s);
}
就其本身而言,这可能不是什么大问题,但它确实强调了对于完全兼容的c++编译器(即支持导出的编译器),static关键字仍然具有其他任何方式都无法提供的功能。
// bar.h
export template <typename T>
int b1 (T const & t);
// bar.cc
#include "bar.h"
template <typename T>
int b1 (T const & t)
{
foo(t);
}
// foo.cc
#include "bar.h"
namespace NS
{
namespace
{
struct S
{
};
void foo (S const & s); // Will be found by different TU 'bar.cc'
}
}
void b2()
{
NS::S s;
b1 (s);
}
确保未命名名称空间中的函数不会在使用ADL的模板中找到的唯一方法是将其设置为静态。
为现代c++更新
从c++ '11开始,未命名命名空间的成员隐式具有内部链接(3.5/4):
未命名的名称空间或在未命名的名称空间中直接或间接声明的名称空间具有内部链接。
但与此同时,14.6.4.2/1被更新,删除了链接(这来自c++ '14):
对于后缀表达式是依赖名称的函数调用,候选函数使用
通常的查找规则(3.4.1,3.4.2),除了:
对于使用非限定名称查找的部分(3.4.1),只找到模板定义上下文中的函数声明。
对于使用关联名称空间的查找部分(3.4.2),只会找到在模板定义上下文或模板实例化上下文中找到的函数声明。
结果是静态名称空间成员和未命名名称空间成员之间的这种特殊区别不再存在。