简体   繁体   English

二元运算符重载,隐式类型转换

[英]binary operator overloading, implicit type conversion

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 
  }
}

I have just created a similar topic regarding my problem over here binary operator overloading; 我刚刚在这里创建了一个关于我的问题的类似主题二元运算符重载; implicit type conversion . 隐式类型转换 It can be deleted I guess because it is not explicit enough about the problem I am encountering. 我可以删除它,因为它对我遇到的问题不够明确。

Why is that operator== works fine and operator&& causes ambiguities? 为什么operator==正常工作, operator&&导致歧义? How do I solve this problem? 我该如何解决这个问题? I can surely write down two more overloads of operator&& ( bool , my_bool ), ( my_bool , bool ). 我当然可以写下两个operator&&boolmy_bool ),( my_boolbool )的my_bool That is a messy solution though 这是一个混乱的解决方案

The builtin operator&& is a context in which expressions are contextually converted to bool . 内置operator&&是一个上下文,表达式在上下文中转换bool Other such contexts include for example the condition of if , for , while and the conditional operator ? 其他这样的上下文包括例如ifforwhile和条件运算符的条件? .

Quoting N4296, §4/4 (the latest publicly available draft before C++14): 引用N4296,§4/ 4 (C ++ 14之前的最新公开草案):

Certain language constructs require that an expression be converted to a Boolean value. 某些语言结构要求将表达式转换为布尔值。 An expression e appearing in such a context is said to be contextually converted to bool and is well-formed if and only if the declaration bool t(e); 在这样的上下文中出现的表达式e被称为在上下文中被转换为bool并且当且仅当声明bool t(e);才是格式良好的bool t(e); is well-formed, for some invented temporary variable t (8.5). 对于一些发明的临时变量t (8.5),其形式良好。

Basically, this means that there is an "impicit explicit conversion to bool " in these contexts. 基本上,这意味着在这些背景下存在“明显转换为bool ”。 Or, to illustrate this further, you can think of the following two lines being one and the same: 或者,为了进一步说明这一点,您可以认为以下两行是同一个:

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

Therefore, the compiler must consider the explicit operator bool() when doing overload resolution for operator&& , but has to ignore it when doing overload resolution for operator== (since that operator does not force a " bool context" .. you can also compare numbers, strings, ...). 因此,编译器在为operator&&执行重载解析时必须考虑explicit operator bool() ,但在为operator==执行重载解析时必须忽略它(因为该运算符不强制“ bool上下文”...您还可以比较数字,字符串,...)。


The solution in your case is IMO to get rid of the operator&&(const my_bool&, const my_bool&) all together. 您的案例中的解决方案是IMO将所有operator&&(const my_bool&, const my_bool&)一起operator&&(const my_bool&, const my_bool&) After all, it does not produce a more meaningful behavior than what would be possible by relying on the builtin operator&&(bool, bool) . 毕竟,它不会产生比依赖内置operator&&(bool, bool)更有意义的行为。 Establishing a second "boolean context" just isn't something the language was designed for (see below). 建立第二个“布尔上下文”并不是该语言的设计 (见下文)。

If you want to keep this operator, say for some side effects, then I see these choices: 如果你想保留这个操作符,比如说有些副作用,那么我会看到这些选择:

  • Be explicit at the call site. 在呼叫站点明确。 That is: 那是:

     if (static_cast<my_bool>(a) && static_cast<my_bool>(b)) { /* ... */ } 
  • Be explicit at the definition site: Provide additional definitions for operator&&(my_bool const &, bool) , operator&&(bool, my_bool const &) . 明确定义站点:为operator&&(my_bool const &, bool)operator&&(bool, my_bool const &)提供其他定义。 These then should rule out both operator&&(my_bool const &, my_bool const &) as well as operator&&(bool, bool) because the later are less specific. 然后这些应该排除operator&&(my_bool const &, my_bool const &)以及operator&&(bool, bool)因为后者不太具体。 Adding these definitions to your class 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; } 

Turns out one can "establish a boolean context", using CRTP: 事实证明,可以使用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 ) Ideone

My first thought on this is that the arguments to the compiler's built-in operator&& are (bool, bool) , so my_bool's explicit bool operator can be invoked - since you are in effect, requesting an explicit conversion. 我的第一个想法是编译器的内置operator&&(bool, bool) ,因此可以调用my_bool的显式bool运算符 - 因为您生效,请求显式转换。

However, I can't find any reference in the standard as to whether a variable appearing on the right hand side of && should invoke an explicit conversion to bool. 但是,我在标准中找不到任何关于出现在&&右侧的变量是否应该调用显式转换为bool的引用。

Here's the complete error output from apple clang (once the source code above is fixed): 这是apple clang的完整错误输出(一旦上面的源代码被修复):

./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.

So how do I fix it? 那么我该如何解决呢?

Remove the user-defined && operator. 删除用户定义的&&运算符。

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
    }
}

The code bellow works in the same manner for both == and &&. 对于==和&&,下面的代码以相同的方式工作。 The class equality is triggered only when are of the same type. 仅当属于同一类型时才会触发类相等性。

#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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM