C++で`*A == *B`の比較がC2666エラーになる原因と解決方法の一例
環境前提
下記で起きました。
- Visual C++ 2022 MFC 14.3
- C++20
MFCであることは多分関係ないです。
はじめに
C++でポインタのデリファレンスを利用してオブジェクトを比較しようとした際に、以下のようなエラーに直面しました。
重大度レベル コード 説明 プロジェクト ファイル 行 抑制状態 詳細
エラー C2666 'CHoge::operator ==': オーバーロードされた関数は同様の変換を行います code huhuhu.cpp 810
このエラーの発生時にはビルド出力に下記が出力されました。
huhuhu.cpp(n,m): error C2666: 'CHoge::operator ==': オーバーロードされた関数は同様の変換を行います
1> source.h(i,j):
1> 'BOOL CHoge::operator ==(const CHoge &)' の可能性があります
1> source.h(i,j):
1> または 'BOOL CHoge::operator ==(const CHoge &)' [合成された式 'y = = x']
1> huhuhu.cpp(n,m):
1> 引数リスト '(CHoge, CHoge)' を一致させようとしているとき
このエラーが発生する原因と、その解決方法の一例について解説します。
免責
本稿はChatGPTを用いて原因を検証していった際のまとめです。
解説した方法で解決したことは事実ですが、その他にはハルシネーションが発生している可能性があることをご了承ください。
本稿の解説を鵜呑みにして発生した問題についてその一切に責任を持ちません。
エラーの再現コード
問題となったコード
以下は、エラーを再現するコードの例です。
class CHoge {
public:
BOOL operator==(const CHoge& other); // const 修飾なし
};
int main() {
CHoge* A;
CHoge* B;
if (*A == *B) { // この行でエラーが発生
// 比較処理
}
return 0;
}
このコードをコンパイルすると、operator==
の呼び出しが曖昧であるというエラーが発生します。
エラーの原因
エラーが発生した主な原因は、operator==
メンバ関数が const
修飾されていなかったことです。
const
が必要なのか?
なぜ C++では、const
修飾が付いていないメンバ関数は、const
なオブジェクトから呼び出すことができません。
*A
や *B
のようなポインタのデリファレンス結果は一時オブジェクトとして扱われ、暗黙的に const
な参照として解釈されることがあります。このとき、非 const
な operator==
を呼び出そうとすると、以下のような曖昧さが発生します:
const
修飾がないため、一時オブジェクトに対して適切なoperator==
が見つからない。- 比較のために一時的に生成される参照の扱いが不明確になり、エラーが発生する。
解決方法
修正後のコード
以下のように、const
修飾を追加することで問題を解決できます。
CHoge
クラス
修正後の class CHoge {
public:
BOOL operator==(const CHoge& other) const; // const 修飾を追加
};
operator==
の定義
修正後の BOOL CHoge::operator==(const CHoge& other) const { // const 修飾を追加
// 比較ロジック
return TRUE;
}
この修正により、const
なオブジェクトや参照を使用した場合でも、operator==
を正しく呼び出せるようになります。
まとめ
問題の原因
-
operator==
にconst
修飾がなかったこと。- ポインタのデリファレンス結果が
const
として扱われる場合があり、非const
メンバ関数が呼び出せなかった。
- ポインタのデリファレンス結果が
修正のポイント
-
const
修飾を付与することで、比較処理がconst
なオブジェクトでも動作するようにする。BOOL operator==(const CHoge& other) const;
結果
この修正により、ポインタのデリファレンス結果を使った比較(*A == *B
)でもエラーが発生せず、期待通りの動作をするようになりました。
あとがき
海外サイトも英語で探してみたけどてんでこの理由で引っかかってるケースを取り上げてなかった。
(もちろん俺の目に入った範囲でという話だが。)
おかげさまで内心涙目になりながら解決方法を探してひたすらGPTで壁打ちしてました。
解決方法見つかったのでよかったぁ。
理屈も別途調べて嘘も破綻もなさそうだからこれで良し。
こういう壁打ちができるのは良いよねAI。
比較オペレータはコピーを作成する意味が無いので特殊な場合除き全部constでええんちゃうかな。
近年のプログラマーなら常識なのかもだが、俺は内部的にはVC++2015のMFCのコードしか基本弄らんので知らんかった。
VS2022のインストールも頭の固い阿呆のせいで色々面倒だったが、それは別の話。
Discussion