関数のオーバーロードが失敗する:なぜこれらの演算子が衝突したのか?
-
03-07-2019 - |
質問
エンジンとアプリケーションという2つの主要な名前空間を含む大きな大きなコードベースがあります。
エンジンはvector3クラスを別のvector3クラスのtypedefとして定義します。vector3クラスではなく、エンジンのネームスペースにある等価演算子を使用します。また、アプリケーションの名前空間に等値演算子を含むクラスをアプリケーションに追加しました。
コンパイルしようとしたとき、適切ではない等価演算子が見つからなかったため、無関係であるが近くのvector3比較は失敗しました。競合が発生しているのではないかと疑ったため、等値演算子を追加したクラスに移動し、コンパイルに成功しました。
// engine.h
namespace Engine
{
class Vector3Impl { ... };
typedef Vector3Impl Vector3;
bool operator==(Vector3 const &lhs, Vector3 const &rhs) { ... }
}
// myfile.cpp
#include "engine.h"
namespace application
{
class MyClass { ... };
bool operator==(MyClass const &lhs, MyClass const &rhs) { ... }
void myFunc(...)
{
if ( myClassA == myClassB ) { ... } // builds
}
void anotherFunc(...)
{
Engine::Vector3 a, b;
...
if ( a == b ) { ... } // fails
}
}
しかし、それについて考えた後、コンパイルが失敗した理由がわかりません。 vector3sから私のクラスへ、またはその逆への暗黙的な変換はなく、引数に依存するルックアップは、エンジン名前空間から等値演算子をプルして、一致させる必要があります。
サンプルC ++プロジェクトでこのバグを再現しようとしましたが、それは壊れません。この大きな問題を引き起こしている大きな大きなコードベースに何かがあるはずですが、どこから探し始めればいいのかわかりません。不正な「エンジンを使用する」の反対のようなものですか?誰でもアイデアはありますか?
解決
C ++標準、3.4.4.2宣言:
関数呼び出しの各引数タイプTには、0個以上の関連する名前空間のセットと0個のセットがあります 考慮される関連クラス以上。名前空間とクラスのセットは、次のタイプによって完全に決定されます。 関数の引数(およびテンプレートテンプレートの引数の名前空間)。 Typedef名とusing宣言 このセットに貢献しないタイプを指定するために使用されます。
ADLはtypedefで動作しません。
他のヒント
以前、引数依存ルックアップ(Koenigルックアップ-@igorに感謝)を持たないコンパイラで同じ問題に遭遇しました(VC6と思います)。これは、演算子を見つけると、それが囲んでいる名前空間を調べるだけであることを意味します。
では、使用しているコンパイラを教えてください。
別のコンパイラに移動すると解決しました。
非常に不便です。
bool operator==(Vector3 const &lhs, Vector3 const &rhs) { ... }
クラスで定義された等値演算子の標準的な定義には、rhsという1つの引数のみが必要です。 lhsはこれです。 ただし、これが問題の解決策になるかどうかはわかりません。
これは私が書くものです:
クラスVector3 { bool operator ==(const Vector3& rhs)const {...} };