2016-04-03 18 views
3
class my_bool { 
    private: 
    bool value; 
    public: 
    my_bool(bool value) : value(value) {} 
    explicit operator bool() { return value }; 

    friend my_bool operator==(const my_bool & instance_1, const my_bool & instance_2); 
    friend my_bool operator&&(const my_bool & instance_1, const my_bool & instance_2); 

}; 

void main(){ 
    my_bool a = true; 
    bool b = false; 

    if(a == b){ 
    // do something 
    } 

    if(a && b){ 
    // do something 
    } 
} 

私はここで私の問題に関して同様のトピックを作成しましたbinary operator overloading; implicit type conversion。それは私が遭遇している問題について十分に明示的ではないので、削除することができます。バイナリ演算子のオーバーロード、暗黙の型変換

なぜoperator==がうまく動作し、operator&&があいまいになるのですか?この問題をどうやって解決するのですか? operator&&bool,my_bool)、(my_boolbool)の2つのオーバーロードを確実に書き留めることができます。これは面倒な解決策ですが、

+3

'void main()' *いいえ*。 'int main()' –

+3

なぜなら、 '&&'は、引数が文脈上bool *に変換され、 'explicit'とマークされたコンバータを許可するコンテキストであるからです。 '?'、 '||'、 '?'、 '' do''、 'while'、' static_assert'、 'noexcept'の最初のオペランド –

+0

実際に' explicit'キーワードが表示され、 'my_bool'から' bool'への暗黙の変換は許されません。そのような変換は、明示的に '(bool)my_bool_instance'だけ行うことができます。つまり、コンパイラは 'my_bool'を暗黙の変換にboolすることを考慮しないでください。 – user3600124

答えて

5

組み込みoperator&&は式は文脈boolに変換されるコンテキストです。他のそのような状況は、例えば、if,for,whileおよび条件付き演算子?の条件を含む。

特定の言語構造は、式はブール値に変換する必要が:N4296, §4/4(C++ 14の前に、最新の公に利用可能な案を)引用

。そのような文脈に現れる表現e は、文脈上boolに変換されたと言われており、 宣言bool t(e);が整形式である場合にのみ、整形式変数t(8.5)の場合に整形式となる。

基本的に、これは、これらのコンテキストで「暗黙の明示的な変換をboolにする」ことを意味します。それとも、これをさらに説明するために、次の2つの行が1と同じであることを考えることができます。

a && b 
static_cast<bool>(a) && static_cast<bool>(b) 

そのため、コンパイラはoperator&&のためのオーバーロードの解決を行うときexplicit operator bool()を検討したが、やってたときに、それを無視している必要がありますoperator==の過負荷解決(演算子は "boolコンテキスト"を強制しないので、数値、文字列なども比較できます)。


あなたのケース内の溶液はすべて一緒operator&&(const my_bool&, const my_bool&)を取り除くためにIMOです。結局のところ、組み込み関数operator&&(bool, bool)に頼ることによって可能なものよりも意味のある動作を生成しません。 2番目の「ブール値のコンテキスト」を確立することは、言語が(以下を参照)用に設計されたものではありません。

あなたがこの演算子を保持したい場合は、私はこれらの選択肢を参照してください、いくつかの副作用のために言う:

  • は、呼び出しサイトで明示して下さい。それは次のとおりです。

    if (static_cast<my_bool>(a) && static_cast<my_bool>(b)) { /* ... */ } 
    
  • は定義サイトで明示して:operator&&(my_bool const &, bool)operator&&(bool, my_bool const &)のための追加的な定義を提供します。これらは、operator&&(my_bool const &, my_bool const &)operator&&(bool, bool)の両方を除外する必要があります。これは、あまり具体的でないためです。あなたのクラスshould mitigate the issueにこれらの定義を追加:

    friend my_bool operator&&(const my_bool & lhs, bool rhs) { 
        // Delegate to operator&&(const my_bool &, const my_bool &) 
        return lhs && my_bool(rhs); 
    } 
    friend my_bool operator&&(bool lhs, const my_bool & rhs) { 
        // Delegate to operator&&(const my_bool &, const my_bool &) 
        return my_bool(lhs) && rhs; 
    } 
    

は1つがCRTPを使用して、 "ブール値コンテキストを確立" することができ判明:

#include <iostream> 
using namespace std; 

template<typename T> 
struct bool_context { 
    friend T operator&&(T const & lhs, bool rhs) { 
     return lhs && T(rhs); 
    } 
    friend T operator&&(bool lhs, T const & rhs) { 
     return T(lhs) && rhs; 
    } 
    friend T operator||(T const & lhs, bool rhs) { 
     return lhs || T(rhs); 
    } 
    friend T operator||(bool lhs, T const & rhs) { 
     return T(lhs) || rhs; 
    } 
}; 

struct my_bool : bool_context<my_bool> { 
    bool value; 
    my_bool(bool v) : value(v) {} 
    explicit operator bool() { return value; }; 
    friend my_bool operator&&(my_bool const & lhs, my_bool const & rhs) { 
     cout << "my_bool::operator&&" << endl; 
     return lhs.value && rhs.value; 
    } 
    friend my_bool operator||(my_bool const & lhs, my_bool const & rhs) { 
     cout << "my_bool::operator||" << endl; 
     return lhs.value || rhs.value; 
    } 
}; 


int main(int, char**) { 
    my_bool a = true; 
    bool b = false; 
    cout << "a && b => "; a && b; // my_bool::operator&& 
    cout << "b && a => "; b && a; // my_bool::operator&& 
    cout << "a && a => "; a && a; // my_bool::operator&& 
    cout << "b && b => "; b && b; cout << endl; 
    cout << "a || b => "; a || b; // my_bool::operator|| 
    cout << "b || a => "; b || a; // my_bool::operator|| 
    cout << "a || a => "; a || a; // my_bool::operator|| 
    cout << "b || b => "; b || b; cout << endl; 
    return 0; 
} 

Ideone

+0

OP質問の2番目の部分に対する回答がありますか(コードの修正方法) –

+0

@MooingDuck No: 'operator &&'のコンテキストのため、明示的な変換を(暗黙的に)演算子&&(bool、bool) '実行可能なオーバーロード。 –

+0

この例のコードの結果は、私が理解できないものです... 'operator &&(my_bool、my_bool)'が呼び出され、 'operator &&(bool、my_bool)'を期待していました。 – user3600124

1

コンパイラの組み込みの引数が(bool, bool)であるため、明示的な変換を要求しているので、my_boolの明示的なbool演算子を呼び出すことができます。

しかし、標準では、& &の右側に表示される変数がboolへの明示的な変換を呼び出す必要があるかどうかはわかりません。

(上記のソースコードが固定されたら)ここでリンゴ打ち鳴らすからの完全なエラー出力です:

./nod.cpp:45:10: error: use of overloaded operator '&&' is ambiguous (with operand types 'my_bool' and 'bool') 
    if(a && b){ 
     ~^~ 
./nod.cpp:33:20: note: candidate function 
    friend my_bool operator&&(const my_bool & instance_1, const my_bool & instance_2); 
       ^
./nod.cpp:45:10: note: built-in candidate operator&&(_Bool, _Bool) 
    if(a && b){ 
     ^
1 error generated. 

だから私はそれをどのように修正するのですか?

ユーザー定義の& &演算子を削除します。

class my_bool { 
private: 
    bool value; 
public: 
    my_bool(bool value) : value(value) {} 
    explicit operator bool() { return value; } 

    friend my_bool operator==(const my_bool & instance_1, const my_bool & instance_2); 
// friend my_bool operator&&(const my_bool & instance_1, const my_bool & instance_2); 

}; 

int main(){ 
    my_bool a = true; 
    bool b = false; 

    if(a == b){ 
     // do something 
    } 

    if(a && b){ 
     // do something 
    } 
} 
+0

参照のために[expr.log.and]/1を参照してください。 –

+0

@ M.M多くのおかげです。 –

+0

'a && b'は' a'と 'b'の両方が' bool'型であるときだけ 'bool'型の結果を返すべきです。さもなければ、 'my_bool'型の結果を与えるべきです。それは非常に重要です – user3600124

0

をコードは、==と&の両方に対して同じように動作します。 クラスの等価性は、同じ型である場合にのみトリガされます。

#include <stdio.h> 

class my_bool { 
private: 
    bool v{false}; 
    public: 
    my_bool() : v(v) {}; 
    operator bool(){return v;} 

    friend bool operator==(const my_bool a, my_bool b){ 
      printf("operator==\n");return a.v==b; 
     } 
     friend bool operator&&(const my_bool a, my_bool b){ 
      printf("operator&&\n");return a.v&&b; 
     } 
}; 

int main(int argc, char **argv) 
{ printf("Starting\n"); 
    bool a=true,b=true; 
    my_bool A{},B{},R{}; 

    a==b;a&&b; 
    a==A;a&&A; 
    A==b;A&&b; 
    A==B;A&&B; 
} 
+0

これはあいまいさを修正し、 'my_bool a = false'のような暗黙の変換を' bool'から 'my_bool'にもう許可しません – user3600124

関連する問題