voidもしくはboolを返す
書いているC++プログラムの一か所に出てきた既視感のある部分についての備忘録。
該当部分は次の4行。
struct bool_proxy { explicit operator bool() const { return true; } friend bool operator ,(bool b, const bool_proxy&) { return b; } };
こういう使い方をする。
template <typename F> void foo(F&& func, int begin, int end) { bool_proxy bp; // <-- これ(後から追加) for ( auto i = begin; i < end; ++i ) { // std::forward<F>(func)(i); // <-- 最初はこうだった if ( !(std::forward<F>(func)(i), bp) ) break; } } //---------------------------------------------------------- std::vector<int> vec; auto void_expr = [&](int a) { //もともとあったファンクタ vec.push_back(a); }; auto bool_expr = [&](int a) { //追加したファンクタ if ( a < 5 ) vec.push_back(a); return a < 5; }; foo(void_expr, -99, 100); // -99 ~ +99 foo(bool_expr, -99, 100); // -99 ~ +4
関数foo
はループ中でコールバックfunc
を呼び出すが、「最初はこうだった」とコメントアウトしている通り当初は無条件に呼び出すだけで、func
の戻り値もvoidだった。その後条件によってループをbreakしたいという要求が出てきたので、bool値を返すファンクタを作った(falseが返ってきたときbreak)。
しかし、
- すべての場合にそういう条件をつけたい訳ではない
- もともと使っていたファンクタの戻り値型をvoidからboolに直すのは面倒だ
そこでfoo
を<F>
でオーバーロードしよう思ったが、以下のようなことを考えてやりたくなくなった。
voidな式はtrueと評価し、boolな式はそれ自体として評価する方法はないかと考えた結果、最初に示したbool_proxy
のアイデアを思いついた。「イヤだ」と感じた3つの点は避けられたが、既視感があるようなないような、罠があるようなないような、もっと全然簡単な方法があるようなモヤモヤした状態のまま使っている。
とりあえずbool_proxy
という名前がどこか間違っているような気がしてならない。