2016-10-07 5 views
9

を宣言したテンプレートコンテキストから非常に奇妙なオーバーロードの解決のミニマリストの例である:C++テンプレートのオーバーロードの解決には、テンプレートのインスタンス化の後にここで

#include <iostream> 

// Types // 
struct I { int v; }; 

template <class T> 
struct D { T t; }; 

// Functions // 

// Overload 1 
template <class T> 
I f(T) { return {1}; } 

// Template indirection that calls f(T) 
template <class T> 
I g(D<T>) { return f(T{}); } 

// Non template indirection that calls f(T) 
I h(D<I>) { return f(I{}); } 

int main() { 
    std::cout 
     << f(I{}).v  // f(I{}) overload called directly 
     << "\n"   // => overload 1 called 
     << h(D<I>{}).v // f(I{}) called though non-template 
     << "\n"   // => overload 1 called 
     << g(D<I>{}).v // f(I{}) called though template 
     << "\n";  // => overload 2 actually called ??? 
} 

// Overload 2 
// Should not be reachable as declared after all f(...) calls. 
// If was a candidate, would be chosen over 1. 
I f(I) { return {2}; } 

これはI場合は理由ADLに関連すると思われます名前空間に置かれる "overload 1"は常に呼び出されます。

私が知っているのは、呼び出しがテンプレートのインスタンス化ポイント(main)から行われたかのようにADLが実行されていることです。

テンプレート定義で使用される依存名の場合、テンプレート引数がわかるまでルックアップが延期されます。その時点で、ADLはテンプレートから見える外部リンケージ(C++ 11まで)で関数宣言を調べます。非ADLルックアップはテンプレート定義コンテキストから見える外部リンケージ(C++ 11まで)で関数宣言のみを調べます。 http://en.cppreference.com/w/cpp/language/unqualified_lookup#Template_definition

しかし、ここでは "過負荷2は" main後に宣言されました! mainは、gfのインスタンスポイントであるため、と宣言された関数のみが、mainの前にオーバーロード候補と想定されていました。

gはテンプレートであり、hgの同等のテンプレート関数ではない)が "Overload 1"を呼び出すことに関連していることに注意してください。

「オーバーロード2」は、mainの後で宣言されました。

この動作は、clang ++(3.8.1)およびg ++(6.2.1)で再現されています。

答えて

5

[temp.dep.candidate]/1

コールが悪い形成されるだろうか、関連付けられた名前空間内の 検索がすべて でこれらの名前空間に導入された外部結合を持つすべての機能 宣言を検討していたより良い一致を見つけたい場合テンプレート定義およびテンプレートのインスタンス化コンテキストにある という宣言を考慮するだけでなく、 プログラムには未定義の動作があります。

また

[temp.point]/6、強調鉱山:

関数テンプレートの特殊[...]翻訳単位内のインスタンスの複数 点を有していてもよく、加えて、点を します 翻訳単位内でインスタンス化のポイントを持つそのような 特殊化については、 インスタンシエーションとも見なされます。 [...]インスタンス化の2つの異なる点 がテンプレート定義に異なる定義を与える場合は、 one-definitionルール([basic.def。odr])、プログラムは不正な形式であり、 診断は必要ありません。

プログラムの動作は未定義です。

+0

これは、ライブラリの名前空間にオーバーロードを追加することに対して、もう一つの欠点を追加します。そのような追加は、このオーバーロードがライブラリコードで選択された場合、未定義の動作につながる可能性があります。その合理的ではなく、ルールを知っていた。 –

関連する問題