次のコードを考えてみましょう。このコードでは、オーバーロードの場所がf
直感的ではない動作を引き起こしています。このコードは、Clang 3.4.1 と gcc 4.8 の両方で警告なしでコンパイルされます。
template<typename T>
struct A
{
static const int value = sizeof(f(T()));
};
struct B
{
};
struct D : B
{
};
char f(B);
// instantiates A<D>, unqualified name lookup finds f(B) via ADL
static_assert(A<D>::value == sizeof(f(B())), ""); // passes
long f(D); // but wait, f(D) would be a better match!
// A<D> is already instantiated, f(D) is not found
static_assert(A<D>::value == sizeof(f(B())), ""); // passes
C++11 標準は、上記のコードが未定義の動作を呼び出すことを示唆しています。
【温度差候補】
テンプレート パラメーターに依存する関数呼び出しの場合、次の点を除いて、通常の検索規則を使用して候補関数が検索されます。
- 非修飾名ルックアップまたは修飾名ルックアップを使用したルックアップの部分では、テンプレート定義コンテキストからの関数宣言のみが検出されます。
- 関連付けられた名前空間を使用したルックアップの部分では、テンプレート定義コンテキストまたはテンプレート インスタンス化コンテキストのいずれかにある関数宣言のみが検出されます。
関数名が修飾されていない ID であり、呼び出しの形式が正しくないか、関連付けられた名前空間内のルックアップで、すべての翻訳単位のそれらの名前空間に導入された外部リンケージを持つすべての関数宣言が考慮された場合に、より適切な一致が見つかる場合。これらの宣言がテンプレート定義およびテンプレートのインスタンス化コンテキストで見つかった場合、プログラムは未定義の動作をします。
上記のコードは、この特定の未定義の動作を呼び出しますか? 高品質の実装が警告を報告することを期待できますか?