カスタムバリアントのような型からの明示的な変換を実装するために、プロジェクトでテンプレート化された明示的な変換演算子をいじっています。私の問題を再現する最小限の例は次のようになります (C++14 モード):
#include <iostream>
#include <stdexcept>
#include <cmath>
using namespace std;
class A
{
public:
template<typename T> explicit operator T() const // 1
{
cout << "operator T" << endl;
return T();
}
template<typename T> explicit operator const T&() const // 2
{
cout << "operator const T&" << endl;
throw runtime_error("operator const T&");
}
template<typename T> explicit operator T&() // 3
{
cout << "operator T&" << endl;
throw runtime_error("operator T&");
}
};
int main(int, char**)
{
try
{
const A& a = A();
cout << abs(static_cast<double>(a) - 3.14) << endl;
}
catch (const runtime_error&)
{
}
return 0;
}
私が直面した問題は、 static_cast 変換用に選択された演算子です。GCC では、予想される (1) ケースのようなものです。出力は次のとおりです。
operator T
3.14
しかし、Clang は次の出力でこれをコンパイルすることを拒否します。
main.cpp:37:20: error: ambiguous conversion for static_cast from 'const A' to 'double'
cout << std::abs(static_cast<double>(a) - 3.14) << endl;
^~~~~~~~~~~~~~~~~~~~~~
main.cpp:10:32: note: candidate function [with T = double]
template<typename T> explicit operator T() const
^
main.cpp:16:32: note: candidate function [with T = double]
template<typename T> explicit operator const T&() const
^
1 error generated.
(1) ではなく、変換シーケンスで追加のコンストラクター呼び出しが必要になるように見えるのに、Clang が変換 (2) を考慮するのはなぜですか? そして、そうするのは正しいですか(そしてGCCは間違っています)?