忍者ブログ

VIEWブログ

tk-xleaderのブログ。C++などプログラミングの話題が中心です。

boost::operators::equality_comparable2とC++20の比較演算子の問題

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

boost::operators::equality_comparable2とC++20の比較演算子の問題

C++20で比較演算子のオーバーロード解決のルールが大幅に変更になりました。
その影響で、boost::operators::equality_comparable2が特定のケースでコンパイルエラーが生じる結果となることが報告されています*1

問題のコードは大体こんな感じ。

#include <boost/operators.hpp>

struct my_type : boost::equality_comparable2<my_type, double> {
    explicit my_type(double mem) : mem_{mem}{}
    double mem_{0};
    operator double() {
        return mem_;
    }
    bool operator==(my_type l) {
        return l.mem_ == mem_;
    }
}; 


int main() {
    my_type x{0};
    return x == double{0};
}
(下記issueから引用)
どういうことかというと、C++20では、「x==y」という式に対して、「y==x」と式を書き換えた場合を加えてオーバーロード解決をしようとします。 すると、x==double{0}; という式に対して、double{0}==xという式に書き換えた場合の等価演算子も候補に入るわけですね。
ところで、boost::equality_comparable2<X, Y>は、 bool operator==(const Y& y, const X& x){ return x==y;} という形で、operator==(X, Y)のみ用意しておけば、自動的にoperator==(Y, X)も実装されるということです。

じゃあ、上のケースで、x==double{0}という式はどうなるか。C++17までであれば、mytypeからdoubleへの暗黙変換が可能なので、double同士の組み込みの比較演算子のみがマッチするため、それが選ばれるわけです。

ところが、C++20だと、x==double{0};が、double{0}==x;と書き換えられた式についてもオーバーロード解決にに加わるため、equality_comparable2内で定義されるfriend関数である、operator(const double&, const mytype&);がマッチしてしまうんですよね。しかも、double同士の組み込みの演算子と違い、変換なしでぴったり一致してしまうので、こちらが選ばれてしまうわけです。
すると、operator(const double&, const mytype&)内で、再びmytype == doubleの比較をしてしまうため、無限再帰をしてしまうわけです。

*1 https://github.com/boostorg/utility/issues/65
PR

コメント

プロフィール

HN:
tk-xleader
Webサイト:
性別:
男性

カテゴリー

P R