4

@Xeo の優れたc++-faq質問から: C++11 では safe-bool イディオムは廃止されましたか? explicitC++03 でセーフ bool が必要なコンテキストでは、ユーザー定義の変換boolが自動的に呼び出されるため、セーフ bool イディオムが不要になったことを知りました。

&&ただし、 、 、などの演算子をオーバーロードする機能は、これを回避しているようです||!

operator!への変換の提供を超えて が必要なケースは、やboolのようにまれですが、C++ 式ツリーの実装 (遅延実行および記号演算手法に使用される) では、これらをオーバーライドする必要があります。operator&&operator||

ユーザー定義の演算子が呼び出されているときに「コンテキスト変換」が行われますか? operator&&またはの定義がoperator||「セーフブール」を実装する型と「コンテキスト変換」用に設計された型の両方で正しく機能することを確認するには、どのような SFINAE 呪文が必要ですか?


明確にするために、与えられた:

class uses_safe_bool
{
    void f() {};
    typedef void (uses_safe_bool::* safe_bool)();

public:
    operator safe_bool() const { return (rand() & 1)? &uses_safe_bool::f: 0; }
};

class uses_explicit_bool
{
public:
    explicit operator bool() const { return rand() & 1; }
};

template<typename T>
class deferred_expression
{
    // Not convertible to bool
public:
    T evaluate() const;
};

operator||次の式がすべて有効になるために必要な署名は次のとおりです。

deferred_expression<bool> db;
uses_safe_bool sb;
uses_explicit_bool eb;
int i;

auto test1 = sb || db;
auto test2 = eb || db;
auto test3 = true || db;
auto test4 = false || db;
auto test5 = i || db;

これらは異なるオーバーロードを使用します:

auto test6 = db || db;

deferred_expression<int> di;
auto test7 = di || db;

以下はコンパイル時に拒否されます。

std::string s;
auto test7 = s || db;

std::vector<int> v;
auto test8 = v || db;

deferred_expression<std::string> ds;
auto test9 = ds || db;
4

1 に答える 1

4

ルールは C++03 (safe-bool idiom) と C++11 (explicit conversion operator) で同じです: このためのブール演算子をオーバーロードしないでください (短絡動作とデフォルトを失わないようにするため)。正常に動作します)。後者は、組み込みブール演算子のオペランドがコンテキスト変換の対象となるため、たとえば、&&n3290、5.14 論理 AND 演算子 [expr.log.and] からのように機能します。

1 && 演算子は左から右にグループ化します。オペランドは両方とも、コンテキストに応じて bool 型に変換されます (条項 4)

(私のものを強調し、他の演算子についても同様のテキスト)


オーバーロードされた演算子は通常の関数呼び出しであるため、コンテキスト変換は行われません。オーバーロードされたブール演算子が常にオーバーロードの解決を通じて選択されていることを確認してください。たとえば、これは左辺値を無視しています:

struct evil {
    explicit operator bool() const;
};
void operator||(evil&&, evil&&);

evil e;
// built-in operator||
e || e;

// overloaded operator||
evil() || evil()

cv修飾子と値カテゴリtemplate<typename Lhs, typename Rhs> void operator||(Lhs&&, Rhs&&);に関係なく、オペランド型のいずれかがクラス型である場合、ADL を介して が選択されることに注意してください。

于 2011-09-25T03:56:46.770 に答える