2013-02-20 21 views
12

クランでコンパイルすると、それはオーバーロード変換演算子テンプレート

test.cpp:11:12: error: conversion from 'C' to 'double' is ambiguous 
    double x = c; 
     ^ ~ 
test.cpp:4:5: note: candidate function 
    operator int() {return 1;} 
    ^
test.cpp:5:5: note: candidate function 
    operator bool() {return false;} 
    ^
test.cpp:3:27: note: candidate function [with T = double] 
    template <typename T> operator T() {return 0.5;} 
         ^
1 error generated. 

他のコンパイラは同様のエラー、例えば、GCCおよびインテルICLC

を生成し、次のエラーが発生します

struct C 
{ 
    template <typename T> operator T() {return 0.5;} 
    operator int() {return 1;} 
    operator bool() {return false;} 
}; 

int main() 
{ 
    C c; 
    double x = c; 
    std::cout << x << std::endl; 
} 

次の簡単な例を考えてみましょう

operator intoperator boolを削除した場合。それは正常にコンパイルされ、期待どおりに動作します。それらのうちの1つだけを削除すると、それはテンプレート演算子を保持し、operator intと言うと、テンプレート以外のバージョンが常に選択されます。

私の理解では、テンプレートと非テンプレートオーバーロード関数は、彼らは両方とも完全に一致しているか、その両方が同じ変換シーケンスを必要とするという意味で等しい場合にのみ、非テンプレートバージョンが優先されるということです。ただし、この場合、コンパイラは演算子テンプレートを完全一致として認識しません。 boolintの両方のオーバーロードが存在する場合、当然、それらはあいまいとみなされます。要約すると

、私の質問は、なぜオペレータテンプレートがこの場合は完全に一致するとはみなされないということでしょうか?

答えて

4

これは面白いです。セクション13.3.3の重要な部分を読むには2つの方法があります。元の例では必ず関数テンプレートを呼び出す必要がありますが、非テンプレートの1つが削除されたバージョンはあいまいであると主張されるかもしれません。

13.3.3:

実行可能な機能F1は、すべての引数の場合は、別の実行可能な機能F2より良く関数であると定義されている私は、ICS_i(F1)が悪化し、変換シーケンスではありませんICS_i(F2)よりも、その後、

  • いくつかの引数jに対して、ICS_j(F1)はICS_j(F2)よりも良好な変換シーケンスであるか、または、そのされていない場合、

  • コンテキストは、ユーザー定義の変換(8.5、13.3.1.5を参照して、13.3.1.6によって初期化され)と戻り値のタイプF1から宛先タイプ(つまり、初期化されるエンティティのタイプ)への標準変換シーケンスは、返されるタイプがF2から宛先のタイプへの標準の変換シーケンスよりも優れた変換シーケンスです。

  • F1はテンプレートではない関数であり、F2は関数テンプレートの特殊化であり、そうでなければ

  • F1F2関数テンプレート特殊化であり、F1の関数テンプレートは、14.5.6.2に記載の半順序規則に従ってF2のテンプレートより特殊です。

実行可能な機能が他のすべての実行可能な機能よりも優れている場合、それは過負荷解決によって選択された機能です。それ以外の場合は、呼び出しが不正です。例で

、打ち鳴らす正しく3つの実行可能な候補関数のセットを識別する:

C::operator int() 
C::operator bool() 
C::operator double<double>() 

第三の関数テンプレート特殊です。 (私は上記の構文は合法だとは思わないが、あなたは考えている:オーバーロード解決のこの時点では、テンプレートとして扱われるのではなく、特定の関数型を持つ特殊化として)。

唯一の暗黙の変換引数のシーケンス(ICS1)は暗黙的なパラメータで "C&"と "lvalue C"を完全に一致させたので、違いはありません。

この例は、2番目の箇条書きで説明したとおりです。したがって、doubleを返す関数は他の2つより明らかに優れています。

ここでそれは奇妙になります。非常にリテラルな読書では、operator intも3番目の箇条書きのためにテンプレートの特殊化より優れています。 "ちょっと待って、反対称ではない"と言いたいのですが、どうすればF2よりも良くて、F1よりもF2が良いですか?残念ながら、スタンダードは明示的に何も言わない。 "第二の弾丸は第三の弾丸よりも優先されますか?「はい、もちろん一定のF1F2ため。しかし、標準(F1,F2)ための第二の弾丸を満たすこと(F2,F1)適用されないための第三弾を作ることを言っていません。

operator intoperator boolよりも良いとその逆ではないので、他のすべての実行可能な機能より優れた機能である正確に1つの実行可能な機能がまだあります。

標準欠陥として報告する以外に、私はこの奇妙な読書を厳密に支持していません。結果(のようにを削除すると、ではないこの例からのベストは、プログラムを整形式からあいまいなものに変更します!)。私は第3弾がまったく考慮されないうちに第2弾が両方の方法とみなされることを意図していると思います。

これは、機能テンプレートが過負荷解決によって選択されるべきであることを意味し、これは密かなバグです。

+0

標準のあなたの「変わった読書」は非常に面白く、実際にはかなり意味があります。私が正しく理解すれば、演算子intがテンプレートより優れているかどうかは、どちらがF1で、どちらがF2であるかによって決まります。 F1 = op int、F2 = op と考えると、箇条書き3では、F1がF2より優れていると判断して停止します。しかし、F1 = op 、F2 = op intと考えると、弾丸2ではF1が良いと判断し、停止します。しかし、3つがある場合、op intとop boolはもはや他のものよりも優れていないので、あいまいではありません –

6

は、二つの異なる問題にこれを打破するのをしてみましょう:

1.なぜ、これはコンパイラエラーを生成するのでしょうか?

struct C 
{ 
    operator bool() {return false;} 
    operator int() {return 1;} 
}; 

intbool両方が暗黙的にdoubleに変換されるように、コンパイラは使用すべき機能しているかを知ることはできません。使用できる2つの機能があり、どちらも優先されません。

2.なぜテンプレートのバージョンが完全に一致していないのですか?

struct C 
{ 
    template <typename T> operator T() {return 0.5;} 
    operator int() {return 1;} 
}; 

ダブルを要求するときに、なぜoperator int()が呼ばれていますか?

テンプレート以外の関数が呼び出されるのは、テンプレート以外の関数がオーバーロードの解決で優先されるためです。 (Overloading function templates

EDIT: 私が間違っていました! Yan Zhou氏がコメントで述べたように、私が提供したリンクにも述べられているように、テンプレート関数の完全一致が非テンプレート関数よりも優先されます。

私はあなたのコードをテストしました(g ++ 4.7.2でコンパイルされています)、それは期待どおりに機能しました:0.5を返しました。つまり、テンプレート関数が使用されました!

EDIT2: 私は今、あなたが記述した動作を再現できます。 gccで正しく動作するので、これはclangのバグです。

+0

最初の部分は、質問に記載されているように私はすでに考え出した。しかし、第2の部分では、テンプレート以外の関数は、他のアスペクトが等しい場合にのみ、オーバーロードの解決に優先します。この場合、テンプレートは変換を必要とせず、非テンプレート演算子がintまたはboolを返してからdoubleに変換する必要がある間にdoubleを返します。だから私はまだ完璧なマッチではない理由は分からない。あなたが与えたリンクでも、 'f'への2回目の呼び出しは完全一致テンプレートが優先されることを示します。非テンプレート化が優先されるのは、最初と3番目のコールです。 –

+0

@YanZhouあなたは正しいです、私は私の答えを更新しました。しかし、私のアプリケーションはあなたのものとは異なる動作をしているようです。私はgccでそれをテストし、比較のために現在clangをインストールしています。 – Misch

+0

どのGCCバージョンを使用しましたか?私はG ++ 4.7を試しましたが、Clangと同じエラーが出ます。Intel icpcも同じです13.1 –

関連する問題