Як правильно перевірити, чи функція std :: порожня в C ++ 11?


96

Мені було цікаво, як правильно перевірити, чи не std::functionє порожнім. Розглянемо цей приклад:

class Test {
    std::function<void(int a)> eventFunc;

    void registerEvent(std::function<void(int a)> e) {
        eventFunc = e;
    }

    void doSomething() {
        ...
        eventFunc(42);
    }
};

Цей код чудово компілюється в MSVC, але якщо я дзвоню doSomething()без ініціалізації, eventFuncкод, очевидно, виходить з ладу. Це очікувалося, але мені було цікаво, в чому цінність eventFunc? Зазначає налагоджувач 'empty'. Тож я виправив це за допомогою простого оператора if:

   void doSomething() {
        ...
        if (eventFunc) {
            eventFunc(42);
        }
   }

Це працює, але мені все ще цікаво, що таке значення неініціалізованого std::function? Я хотів би написати, if (eventFunc != nullptr)але std::function(очевидно) не є покажчиком.

Чому чисте, якщо працює? У чому магія? І чи це правильний спосіб, як це перевірити?


8
Зверніть увагу, що eventFuncце не лямбда; це a std::function. Ви можете зберігати лямбди в std::functions, але це не одне і те ж.
templatetypedef

3
Ви маєте рацію, я змінив заголовок, щоб уникнути плутанини. Дякую.
NightElfik

Відповіді:


104

Ви перевіряєте не порожню лямбду, а те, чи std::functionзберігається в ній виклична ціль. Перевірка є чітко визначеною і працює, завдяки std::function::operator boolчому дозволяє неявне перетворення в boolу контекстах, де потрібні логічні значення (наприклад, умовний вираз у ifоператорі).

До того ж поняття порожньої лямбди насправді не має сенсу. За лаштунками компілятор перетворює лямбда-вираз у struct(або class) визначення, а змінні, які ви захоплюєте, зберігаються як члени цього struct. Також визначений оператор виклику публічної функції, який дозволяє вам викликати лямбда-сигнал. То що б була порожня лямбда?


Ви також можете написати, if(eventFunc != nullptr)якщо хочете, це еквівалентно коду, який ви маєте у запитанні. std::function визначає operator== та operator!=перевантажує для порівняння з a nullptr_t.


1
== nullptrОднак не робить те саме? Схоже , що це повинно бути перевантаження для ==оператора , що призводить до «порожній» , std::functionщоб порівняти trueпроти nullptr: cplusplus.com/reference/functional/function/operators
Kyle Strand

3
@KyleStrand Так, порівняння з також nullptrбуде працювати, if(eventFunc != nullptr)це рівнозначно if(eventFunc)запитуванню вище.
Преторіан,

3
Технічно std::function::operator boolне допускає неявного перетворення на bool. explicitЗрештою, він позначений , але стандарт робить виняток для певних мовних конструкцій, які очікують булевих виразів, називаючи його "контекстуально перетвореним у bool". Ви можете знайти відповідний фрагмент стандарту та пояснення тут: chris-sharpe.blogspot.com/2013/07/…
bcrist

@bcrist Так, я усвідомлюю, що булевим оператором перетворення є explicit, тому я обережно заявив , що допускає неявне перетворення boolв контексти, де потрібні булеві значення . Це саме те, що відбувається у коді, про який йде мова.
Преторіан,

5
@Praetorian Я намагаюся сказати, що стандарт надає фразі "неявне перетворення" дуже конкретне значення, і воно суттєво відрізняється від "контекстного перетворення в bool", що також має цілком конкретне значення. Тут немає взаємин "Є-а". Я розумію, що новачкам, мабуть, не потрібно відразу знати різницю між неявним / явним / контекстним перетворенням, але краще вчити правильні слова підсвідомо, аніж згодом порушувати старі звички.
bcrist

21

Перевірте тут http://www.cplusplus.com/reference/functional/function/operator_bool/

Приклад

// function::operator bool example
#include <iostream>     // std::cout
#include <functional>   // std::function, std::plus

int main () {
  std::function<int(int,int)> foo,bar;
  foo = std::plus<int>();

  foo.swap(bar);

  std::cout << "foo is " << (foo ? "callable" : "not callable") << ".\n";
  std::cout << "bar is " << (bar ? "callable" : "not callable") << ".\n";

  return 0;
}

Вихідні дані

foo не викликається.

панель викликається.


31
Я думаю, що ця відповідь була б більш зрозумілою без swap(). Я думав, що результат буде зворотним, поки я цього не зрозумів.
cp.engr

-1

(Дозвольте дати чітку відповідь.)

Ви можете перевірити, чи std::functionпорожній a , за допомогою std::function::operator bool.

true: якщо об’єкт можна викликати.
false: інакше (об'єкт є порожньою функцією)

Приклад

#include <iostream>
#include <functional>

int main ()
{
    std::function<int(int,int)> foo = std::plus<int>();//assigned: not empty
    std::function<int(int,int)> bar;//not assigned: empty

    std::cout << "foo is " << (foo ? "not empty" : "empty") << ".\n";
    std::cout << "bar is " << (bar ? "not empty" : "empty") << ".\n";

    return 0;
}

Вихідні дані

foo не порожній.
бар пустий.


2
Рядки результатів поміняні місцями.
софіт

@Sophit Ви впевнені? ;)
zwcloud

1
У вашому коментарі зазначено, що foo не порожній, і результат не погоджується. Я згоден з вашим коментарем.
софіт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.