简体   繁体   中英

default behaviour for (bool) cast

classes in the stl, such as unique_ptr will occasionally show examples such as:

// unique_ptr constructor example
#include <iostream>
#include <memory>

int main () {
  std::default_delete<int> d;
  std::unique_ptr<int> u1;
  std::unique_ptr<int> u2 (nullptr);
  std::unique_ptr<int> u3 (new int);
  std::unique_ptr<int> u4 (new int, d);
  std::unique_ptr<int> u5 (new int, std::default_delete<int>());
  std::unique_ptr<int> u6 (std::move(u5));
  std::unique_ptr<void> u7 (std::move(u6));
  std::unique_ptr<int> u8 (std::auto_ptr<int>(new int));

  std::cout << "u1: " << (u1?"not null":"null") << '\n';
  std::cout << "u2: " << (u2?"not null":"null") << '\n';
  std::cout << "u3: " << (u3?"not null":"null") << '\n';
  std::cout << "u4: " << (u4?"not null":"null") << '\n';
  std::cout << "u5: " << (u5?"not null":"null") << '\n';
  std::cout << "u6: " << (u6?"not null":"null") << '\n';
  std::cout << "u7: " << (u7?"not null":"null") << '\n';
  std::cout << "u8: " << (u8?"not null":"null") << '\n';

 *emphasized text* return 0;
}

The line:

 std::cout << "u1: " << (u1?"not null":"null") << '\n';

shows the unique_ptr u1 being directly cast to false if it is tracking a null pointer.

I have seen this behaviour used in other custom classes. How is this managed and what operator decides whether a direct cast to bool such as this returns true or false?

It is implemented as a member conversion operator of the form explicit operator bool() const; . Whether it returns true or false is implemented in the logic of the class itself. For example, this class has an bool conversion operator that returns true if it's data member has value 42 , and false otherwise:

struct Foo
{
  explicit operator bool() const { return n==42; }
  int n;
};

#include <iostream>

int main()
{
  Foo f0{12};
  Foo f1{42};

  std::cout << (f0 ? "true\n" : "false\n"); 
  std::cout << (f1 ? "true\n" : "false\n"); 
}
operator bool();

It's a standard cast-operator to type bool .

Here's an example of how to use it:

class Checked
{
    bool state;

public:
    Checked(bool _state) : state(_state) { }

    explicit operator bool() const {
        return state;
    }
};

Checked c (true);
if (c)
    cout << "true";

Note the explicit keyword. It appeared in C++11 and allows safe conversion of the class to bool, which happens, in short, in the logical context such as if() , while() etc. Without the explicit , bad things could happen, as there's an implicit conversion of bool to numeric types. In C++03 and older it's safer to overload operator ! () operator ! () , which then is tested as if (!!c) .

A conversion operator is used for this functionality:

operator bool(){ return false; }

In C++11 you can also make them explicit

explicit operator bool(){ return true; }

Implicit conversion operators are an error prone endeavour. Consider if unique_ptr had an implicit conversion operator to bool, you could do nonsensical things like...

std::unique_ptr<Thing> x;
int y = 7 + x;

In the above case y would equal 7 + (0 if x is null or 1 if x is non-null)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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