静的が驚くべき効果をもたらすエッジケースが1つあります(少なくとも私にはそうでした)。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
です。
最新の C++ の更新
C++ '11 の時点で、名前のない名前空間のメンバーには暗黙的に内部リンケージがあります (3.5/4):
名前のない名前空間、または名前のない名前空間内で直接的または間接的に宣言された名前空間には、内部リンケージがあります。
しかし同時に、14.6.4.2/1 が更新され、リンケージの言及が削除されました (これは C++ '14 から取得されたものです)。
postfix-expression が従属名である関数呼び出しの場合、次の点を除いて、通常のルックアップ規則 (3.4.1、3.4.2) を使用して候補関数が検索されます。
その結果、静的な名前空間メンバーと名前のない名前空間メンバーの間のこの特定の違いはなくなりました。