Есть один крайний случай, когда статика имеет удивительный эффект (по крайней мере, для меня). Стандарт C ++ 03 заявляет в 14.6.4.2/1:
Для вызова функции, который зависит от параметра шаблона, если имя функции является unqualified-id , но не template-id , функции-кандидаты находятся с использованием обычного правила поиска (3.4.1, 3.4.2) за исключением того, что:
- Для части поиска с использованием поиска без определения имени (3.4.1) найдены только объявления функций с внешней связью из контекста определения шаблона.
- Для части поиска, использующей связанные пространства имен (3.4.2), найдены только объявления функций с внешней связью, найденные либо в контексте определения шаблона, либо в контексте создания шаблона.
...
Приведенный ниже код будет вызывать 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 ++ (т. Е. С поддержкой export
) ключевое слово 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, - сделать ее static
.
Обновление для Modern C ++
Начиная с C ++ '11, члены безымянного пространства имен неявно имеют внутреннюю связь (3.5 / 4):
Безымянное пространство имен или пространство имен, объявленное прямо или косвенно в безымянном пространстве имен, имеет внутреннюю связь.
Но в то же время 14.6.4.2/1 было обновлено, чтобы убрать упоминание о связи (взято из C ++ '14):
Для вызова функции, где выражение postfix является зависимым именем, функции-кандидаты находятся с использованием
обычные правила поиска (3.4.1, 3.4.2) за исключением того, что:
Для части поиска, использующей поиск без определения имени (3.4.1), найдены только объявления функций из контекста определения шаблона.
Для части поиска, использующей связанные пространства имен (3.4.2), найдены только объявления функций, найденные либо в контексте определения шаблона, либо в контексте создания шаблона.
В результате этого конкретного различия между статическими и неназванными членами пространства имен больше не существует.