Що означає "оператор bool () const"


Відповіді:


141

Функції члена форми

operator TypeName()

є операторами перетворення. Вони дозволяють використовувати об'єкти типу класу так, ніби вони мають тип, TypeNameі коли вони є, вони перетворюються на TypeNameвикористання функції перетворення.

У цьому конкретному випадку operator bool()дозволяє використовувати об'єкт типу класу так, ніби він є bool. Наприклад, якщо у вас є об’єкт типу класу з іменем obj, ви можете використовувати його як

if (obj)

Це викликає operator bool(), повертає результат і використовує результат як умову if.

Слід зазначити, що operator bool()це дуже погана ідея, і ви ніколи не повинні її використовувати. Детальне пояснення того, чому це погано, та рішення проблеми див. У розділі "Ідіома безпечного буля".

(C ++ 0x, майбутня редакція стандарту C ++, додає підтримку явних операторів перетворення. Це дозволить вам написати сейф, explicit operator bool()який працює коректно, не переходячи через обручі впровадження ідіоми Safe Bool.)


1
"використовується як бул" помилково означає, що ви можете, скажімо, призначити йому логічне значення. Швидше, у коді плаката він генерує тимчасову змінну типу bool, яка відноситься до моментного значення col, але в подальшому не залежить від об'єкта, який його створив. Крім того, згадка про Safe Bool Idiom є чудовою, але лише для того, щоб зареєструвати, що існують протилежні погляди: порада IMHO "ніколи не використовуй насправді" - вона надає жорсткіші перевірки компілятору щодо безглуздих зловживань ціною більш затуманеного API що може призвести до випадкового неправильного використання.
Тоні Делрой

1
@Tony: Ну, ним можна користуватися так, як ніби це було; оскільки результатом перетворення є значення rvalue ( bool), ні, ви не можете призначити його. Якби це було модифіковане значення lvalue (наприклад bool&), ви могли б призначити його. Що стосується правильності, я стверджую, що an operator bool()завжди є неправильним, оскільки дозволяє використовувати об'єкт класу у величезній кількості ситуацій, коли ви ніколи не хочете, щоб він використовувався. Safe Bool - набагато краща альтернатива.
James McNellis

1
Отже, відповідно до останнього абзацу сьогодні цілком нормально використовувати explicit operator bool(). Чи правильно я розумію?
Zingam

1
Здається, комітет С ++ не погоджується з вами щодо оператора bool (). Принаймні для останньої версії стандарту (наприклад, en.cppreference.com/w/cpp/utility/optional ). Або, можливо, ви мали на увазі, що тільки код STL повинен використовувати це?
Джо Стіл,

1
@JoeSteele - Див stackoverflow.com/a/16615725/2492801 . Явні оператори перетворення безпечні!
Бенджамін Білер

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

7

Я хотів би надати більше кодів, щоб це було зрозуміло.

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

Це визначена користувачем implicitфункція перетворення для перетворення вашого класу в trueабо false.

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

1

Це неявне перетворення в bool. Тобто скрізь, де дозволено неявне перетворення, ваш клас можна перетворити bool, викликаючи цей метод.


1

Як сказали інші, це для перетворення типу, в даному випадку в a bool. Наприклад:

class A {
    bool isItSafe;

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

    ...
};

Тепер я можу використовувати об'єкт цього класу так, ніби це булеве значення:

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

1

Під час написання власного унікального_ptr я знайшов цей випадок. З огляду на std::unique_ptr«Soperator== :

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має a 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ключового слова, ptrin ptr == 0буде перетворено в bool, тоді boolбуде перетворено в int, оскільки bool operator==(int, int)вбудовано і 0є int. Нас чекає неоднозначна помилка дозволу на перевантаження.

Ось мінімальний, повний і перевіряється приклад :

#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
      |                ^~~~~~~~

дзвін :

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.

-4

Іншим поширеним використанням є використання контейнерів std для порівняння рівності ключових значень усередині користувацьких об'єктів

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

2
Цей приклад використовує operator ()not operator bool. Вони абсолютно різні. operator ()є оператором виклику, так що a Comparerможна викликати як функцію. Це operator ()просто повертається bool, але це не означає operator bool, що це просто, що просто дозволяє неявний привід bool.
Michael Dorst
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.