【问题标题】:What is the meaning of "operator bool() const"“运算符 bool() const”是什么意思
【发布时间】:2011-06-03 18:31:52
【问题描述】:

例如:

operator bool() const 
{ 
    return col != 0; 
}

col 是一个整数。 operator bool() const 是如何工作的?

【问题讨论】:

    标签: c++ operators implicit-conversion conversion-operator


    【解决方案1】:

    在编写自己的 unique_ptr 时,我发现了这种情况。给定std::unique_ptr's operator==

    template<class T1, class D1, class T2, class D2>
    bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
    
    template <class T, class D>
    bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept;
    
    template <class T, class D>
    bool operator==(nullptr_t, const unique_ptr<T, D>& x) noexcept;
    

    还有这个来自libstdcxx的测试用例:

      std::unique_ptr<int> ptr;
      if (ptr == 0)
        { }
      if (0 == ptr)
        { }
      if (ptr != 0)
        { }
      if (0 != ptr)
        { }
    

    注意因为ptr 有一个explicit operator bool() const noexcept;,所以operator overload resolution 在这里可以正常工作,例如ptr == 0 选择

     template <class T, class D>
     bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept;`.
    

    如果这里没有explicit关键字,则ptr == 0中的ptr会被转换成bool,那么bool会被转换成int,因为bool operator==(int, int)是内置的,而@ 987654342@ 是int。等待我们的是模棱两可的重载解析错误。

    这是Minimal, Complete, and Verifiable example

    #include <cstddef>
    struct A
    {
        constexpr A(std::nullptr_t) {}
        operator bool() 
        {
            return true;
        }
    };
    
    constexpr bool operator ==(A, A) noexcept
    {
        return true;
    }
    
    constexpr bool operator ==(A, std::nullptr_t) noexcept
    {
        return true;
    }
    
    constexpr bool operator ==(std::nullptr_t, A) noexcept
    {
        return true;
    }
    
    int main()
    {
        A a1(nullptr);
        A a2(0);
        a1 == 0;
    }
    

    gcc

    prog.cc: In function 'int main()':
    prog.cc:30:8: error: ambiguous overload for 'operator==' (operand types are 'A' and 'int')
       30 |     a1 == 0;
          |     ~~ ^~ ~
          |     |     |
          |     A     int
    prog.cc:30:8: note: candidate: 'operator==(int, int)' <built-in>
       30 |     a1 == 0;
          |     ~~~^~~~
    prog.cc:11:16: note: candidate: 'constexpr bool operator==(A, A)'
       11 | constexpr bool operator ==(A, A) noexcept
          |                ^~~~~~~~
    prog.cc:16:16: note: candidate: 'constexpr bool operator==(A, std::nullptr_t)'
       16 | constexpr bool operator ==(A, std::nullptr_t) noexcept
          |                ^~~~~~~~
    

    clang

    prog.cc:30:8: error: use of overloaded operator '==' is ambiguous (with operand types 'A' and 'int')
        a1 == 0;
        ~~ ^  ~
    prog.cc:16:16: note: candidate function
    constexpr bool operator ==(A, std::nullptr_t) noexcept
                   ^
    prog.cc:11:16: note: candidate function
    constexpr bool operator ==(A, A) noexcept
                   ^
    prog.cc:30:8: note: built-in candidate operator==(int, int)
        a1 == 0;
           ^
    prog.cc:30:8: note: built-in candidate operator==(float, int)
    prog.cc:30:8: note: built-in candidate operator==(double, int)
    prog.cc:30:8: note: built-in candidate operator==(long double, int)
    prog.cc:30:8: note: built-in candidate operator==(__float128, int)
    prog.cc:30:8: note: built-in candidate operator==(int, float)
    prog.cc:30:8: note: built-in candidate operator==(int, double)
    prog.cc:30:8: note: built-in candidate operator==(int, long double)
    prog.cc:30:8: note: built-in candidate operator==(int, __float128)
    prog.cc:30:8: note: built-in candidate operator==(int, long)
    prog.cc:30:8: note: built-in candidate operator==(int, long long)
    prog.cc:30:8: note: built-in candidate operator==(int, __int128)
    prog.cc:30:8: note: built-in candidate operator==(int, unsigned int)
    prog.cc:30:8: note: built-in candidate operator==(int, unsigned long)
    prog.cc:30:8: note: built-in candidate operator==(int, unsigned long long)
    prog.cc:30:8: note: built-in candidate operator==(int, unsigned __int128)
    prog.cc:30:8: note: built-in candidate operator==(long, int)
    prog.cc:30:8: note: built-in candidate operator==(long long, int)
    prog.cc:30:8: note: built-in candidate operator==(__int128, int)
    prog.cc:30:8: note: built-in candidate operator==(unsigned int, int)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long, int)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long long, int)
    prog.cc:30:8: note: built-in candidate operator==(unsigned __int128, int)
    prog.cc:30:8: note: built-in candidate operator==(float, float)
    prog.cc:30:8: note: built-in candidate operator==(float, double)
    prog.cc:30:8: note: built-in candidate operator==(float, long double)
    prog.cc:30:8: note: built-in candidate operator==(float, __float128)
    prog.cc:30:8: note: built-in candidate operator==(float, long)
    prog.cc:30:8: note: built-in candidate operator==(float, long long)
    prog.cc:30:8: note: built-in candidate operator==(float, __int128)
    prog.cc:30:8: note: built-in candidate operator==(float, unsigned int)
    prog.cc:30:8: note: built-in candidate operator==(float, unsigned long)
    prog.cc:30:8: note: built-in candidate operator==(float, unsigned long long)
    prog.cc:30:8: note: built-in candidate operator==(float, unsigned __int128)
    prog.cc:30:8: note: built-in candidate operator==(double, float)
    prog.cc:30:8: note: built-in candidate operator==(double, double)
    prog.cc:30:8: note: built-in candidate operator==(double, long double)
    prog.cc:30:8: note: built-in candidate operator==(double, __float128)
    prog.cc:30:8: note: built-in candidate operator==(double, long)
    prog.cc:30:8: note: built-in candidate operator==(double, long long)
    prog.cc:30:8: note: built-in candidate operator==(double, __int128)
    prog.cc:30:8: note: built-in candidate operator==(double, unsigned int)
    prog.cc:30:8: note: built-in candidate operator==(double, unsigned long)
    prog.cc:30:8: note: built-in candidate operator==(double, unsigned long long)
    prog.cc:30:8: note: built-in candidate operator==(double, unsigned __int128)
    prog.cc:30:8: note: built-in candidate operator==(long double, float)
    prog.cc:30:8: note: built-in candidate operator==(long double, double)
    prog.cc:30:8: note: built-in candidate operator==(long double, long double)
    prog.cc:30:8: note: built-in candidate operator==(long double, __float128)
    prog.cc:30:8: note: built-in candidate operator==(long double, long)
    prog.cc:30:8: note: built-in candidate operator==(long double, long long)
    prog.cc:30:8: note: built-in candidate operator==(long double, __int128)
    prog.cc:30:8: note: built-in candidate operator==(long double, unsigned int)
    prog.cc:30:8: note: built-in candidate operator==(long double, unsigned long)
    prog.cc:30:8: note: built-in candidate operator==(long double, unsigned long long)
    prog.cc:30:8: note: built-in candidate operator==(long double, unsigned __int128)
    prog.cc:30:8: note: built-in candidate operator==(__float128, float)
    prog.cc:30:8: note: built-in candidate operator==(__float128, double)
    prog.cc:30:8: note: built-in candidate operator==(__float128, long double)
    prog.cc:30:8: note: built-in candidate operator==(__float128, __float128)
    prog.cc:30:8: note: built-in candidate operator==(__float128, long)
    prog.cc:30:8: note: built-in candidate operator==(__float128, long long)
    prog.cc:30:8: note: built-in candidate operator==(__float128, __int128)
    prog.cc:30:8: note: built-in candidate operator==(__float128, unsigned int)
    prog.cc:30:8: note: built-in candidate operator==(__float128, unsigned long)
    prog.cc:30:8: note: built-in candidate operator==(__float128, unsigned long long)
    prog.cc:30:8: note: built-in candidate operator==(__float128, unsigned __int128)
    prog.cc:30:8: note: built-in candidate operator==(long, float)
    prog.cc:30:8: note: built-in candidate operator==(long, double)
    prog.cc:30:8: note: built-in candidate operator==(long, long double)
    prog.cc:30:8: note: built-in candidate operator==(long, __float128)
    prog.cc:30:8: note: built-in candidate operator==(long, long)
    prog.cc:30:8: note: built-in candidate operator==(long, long long)
    prog.cc:30:8: note: built-in candidate operator==(long, __int128)
    prog.cc:30:8: note: built-in candidate operator==(long, unsigned int)
    prog.cc:30:8: note: built-in candidate operator==(long, unsigned long)
    prog.cc:30:8: note: built-in candidate operator==(long, unsigned long long)
    prog.cc:30:8: note: built-in candidate operator==(long, unsigned __int128)
    prog.cc:30:8: note: built-in candidate operator==(long long, float)
    prog.cc:30:8: note: built-in candidate operator==(long long, double)
    prog.cc:30:8: note: built-in candidate operator==(long long, long double)
    prog.cc:30:8: note: built-in candidate operator==(long long, __float128)
    prog.cc:30:8: note: built-in candidate operator==(long long, long)
    prog.cc:30:8: note: built-in candidate operator==(long long, long long)
    prog.cc:30:8: note: built-in candidate operator==(long long, __int128)
    prog.cc:30:8: note: built-in candidate operator==(long long, unsigned int)
    prog.cc:30:8: note: built-in candidate operator==(long long, unsigned long)
    prog.cc:30:8: note: built-in candidate operator==(long long, unsigned long long)
    prog.cc:30:8: note: built-in candidate operator==(long long, unsigned __int128)
    prog.cc:30:8: note: built-in candidate operator==(__int128, float)
    prog.cc:30:8: note: built-in candidate operator==(__int128, double)
    prog.cc:30:8: note: built-in candidate operator==(__int128, long double)
    prog.cc:30:8: note: built-in candidate operator==(__int128, __float128)
    prog.cc:30:8: note: built-in candidate operator==(__int128, long)
    prog.cc:30:8: note: built-in candidate operator==(__int128, long long)
    prog.cc:30:8: note: built-in candidate operator==(__int128, __int128)
    prog.cc:30:8: note: built-in candidate operator==(__int128, unsigned int)
    prog.cc:30:8: note: built-in candidate operator==(__int128, unsigned long)
    prog.cc:30:8: note: built-in candidate operator==(__int128, unsigned long long)
    prog.cc:30:8: note: built-in candidate operator==(__int128, unsigned __int128)
    prog.cc:30:8: note: built-in candidate operator==(unsigned int, float)
    prog.cc:30:8: note: built-in candidate operator==(unsigned int, double)
    prog.cc:30:8: note: built-in candidate operator==(unsigned int, long double)
    prog.cc:30:8: note: built-in candidate operator==(unsigned int, __float128)
    prog.cc:30:8: note: built-in candidate operator==(unsigned int, long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned int, long long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned int, __int128)
    prog.cc:30:8: note: built-in candidate operator==(unsigned int, unsigned int)
    prog.cc:30:8: note: built-in candidate operator==(unsigned int, unsigned long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned int, unsigned long long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned int, unsigned __int128)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long, float)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long, double)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long, long double)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long, __float128)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long, long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long, long long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long, __int128)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long, unsigned int)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long, unsigned long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long, unsigned long long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long, unsigned __int128)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long long, float)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long long, double)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long long, long double)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long long, __float128)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long long, long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long long, long long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long long, __int128)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long long, unsigned int)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long long, unsigned long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long long, unsigned long long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned long long, unsigned __int128)
    prog.cc:30:8: note: built-in candidate operator==(unsigned __int128, float)
    prog.cc:30:8: note: built-in candidate operator==(unsigned __int128, double)
    prog.cc:30:8: note: built-in candidate operator==(unsigned __int128, long double)
    prog.cc:30:8: note: built-in candidate operator==(unsigned __int128, __float128)
    prog.cc:30:8: note: built-in candidate operator==(unsigned __int128, long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned __int128, long long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned __int128, __int128)
    prog.cc:30:8: note: built-in candidate operator==(unsigned __int128, unsigned int)
    prog.cc:30:8: note: built-in candidate operator==(unsigned __int128, unsigned long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned __int128, unsigned long long)
    prog.cc:30:8: note: built-in candidate operator==(unsigned __int128, unsigned __int128)
    1 error generated.
    

    【讨论】:

      【解决方案2】:

      我想提供更多代码来说明清楚。

      struct A
      {
          operator bool() const { return true; }
      };
      
      struct B
      {
          explicit operator bool() const { return true; }
      };
      
      int main()
      {
          A a1;
          if (a1) cout << "true" << endl; // OK: A::operator bool()
          bool na1 = a1; // OK: copy-initialization selects A::operator bool()
          bool na2 = static_cast<bool>(a1); // OK: static_cast performs direct-initialization
      
          B b1;     
          if (b1) cout << "true" << endl; // OK: B::operator bool()
          // bool nb1 = b1; // error: copy-initialization does not consider B::operator bool()
          bool nb2 = static_cast<bool>(b1); // OK: static_cast performs direct-initialization
      }
      

      【讨论】:

        【解决方案3】:

        另一个常见用途是标准容器对自定义对象内的键值进行相等比较

        class Foo
        {
            public: int val;
        };
        
        class Comparer { public:
        bool operator () (Foo& a, Foo&b) const {
        return a.val == b.val; 
        };
        
        class Blah
        {
        std::set< Foo, Comparer > _mySet;
        };
        

        【讨论】:

        • 此示例使用operator () 而不是operator bool。他们完全不同。 operator () 是调用运算符,因此可以将Comparer 作为函数调用。 operator () 恰好返回 bool,但这并不能使其与 operator bool 相同,后者仅允许隐式转换为 bool
        【解决方案4】:
        operator bool() const 
        {
            return col != 0;
        }
        

        定义类如何转换为布尔值,() 后面的const 用于表示该方法不会发生变异(更改该类的成员)。

        您通常会使用如下运算符:

        airplaysdk sdkInstance;
        if (sdkInstance) {
            std::cout << "Instance is active" << std::endl;
        } else {
            std::cout << "Instance is in-active error!" << std::endl;
        }
        

        【讨论】:

          【解决方案5】:

          正如其他人所说,它用于类型转换,在本例中为bool。例如:

          class A {
              bool isItSafe;
          
          public:
              operator bool() const
              {
                  return isItSafe;
              }
          
              ...
          };
          

          现在我可以像使用布尔值一样使用此类的对象:

          A a;
          ...
          if (a) {
              ....
          }
          

          【讨论】:

            【解决方案6】:

            表单的成员函数

            operator TypeName()
            

            是转换运算符。它们允许使用类类型的对象,就好像它们是TypeName 类型一样,当它们是,它们使用转换函数转换为TypeName

            在这种特殊情况下,operator bool() 允许将类类型的对象用作bool。例如,如果您有一个名为obj 的类类型的对象,您可以将其用作

            if (obj)
            

            这将调用operator bool(),返回结果,并将结果作为if的条件。

            应该注意operator bool() 是一个非常糟糕的主意,你真的不应该使用它。有关它为什么不好以及问题的解决方案的详细说明,请参阅"The Safe Bool Idiom."

            (C++0x,即将发布的 C++ 标准修订版,增加了对显式转换运算符的支持。这些将允许您编写一个安全的 explicit operator bool(),它可以正常工作,而无需跳过实现 Safe Bool 的麻烦成语。)

            【讨论】:

            • “用作布尔值”错误地暗示你可以给它分配一个布尔值。相反,在发布者的代码中,它生成了一个 bool 类型的临时变量,该变量与 col 的瞬时值相关,但此后独立于创建它的对象。此外,提到 Safe Bool Idiom 很棒,但只是为了说明存在相反的观点:恕我直言,“永远不要真正使用它”的建议是最重要的 - 它以更模糊的 API 为代价提供了更严格的编译器检查以防止愚蠢的滥用这可能会导致意外误用。
            • @Tony:嗯,它可以像 bool 一样使用;因为转换的结果是一个右值(bool),不,你不能分配给它。如果它是可修改的左值(例如bool&amp;),那么您可以分配给它。至于正确性,我认为operator bool() 总是不正确的,因为它允许在大量您不想使用的情况下使用类类型对象。 Safe Bool 是一个非常出色的替代方案。
            • 所以根据最后一段,今天使用explicit operator bool()是完全可以的。我理解正确吗?
            • C++ 委员会似乎不同意您对运算符 bool() 的看法。至少对于最新版本的标准(例如en.cppreference.com/w/cpp/utility/optional)。或者你的意思是应该只允许 STL 代码使用它?
            • @JoeSteele - 见stackoverflow.com/a/16615725/2492801。显式转换运算符是安全的!
            【解决方案7】:

            这是用户定义的implicit 转换函数,可将您的类转换为truefalse

            //usage
            bool value = yourclassinstance; //yourclassinstance is converted into bool!
            

            【讨论】:

              【解决方案8】:

              这是到bool 的隐式转换。 IE。只要允许隐式转换,就可以通过调用该方法将您的类转换为bool

              【讨论】:

                猜你喜欢
                • 2013-05-07
                • 2015-09-18
                • 2017-03-29
                • 2011-03-16
                • 2011-07-09
                • 2016-07-23
                • 1970-01-01
                相关资源
                最近更新 更多