Zastanawiałem się, jak prawidłowo sprawdzić, czy std::function
jest pusty. Rozważmy ten przykład:
class Test {
std::function<void(int a)> eventFunc;
void registerEvent(std::function<void(int a)> e) {
eventFunc = e;
}
void doSomething() {
...
eventFunc(42);
}
};
Ten kod kompiluje się dobrze w MSVC, ale jeśli zadzwonię doSomething()
bez inicjalizacji eventFunc
kodu, oczywiście ulega awarii. To jest oczekiwane, ale zastanawiałem się, jaka jest wartość eventFunc
? Debugger mówi 'empty'
. Naprawiłem to za pomocą prostej instrukcji if:
void doSomething() {
...
if (eventFunc) {
eventFunc(42);
}
}
To działa, ale wciąż zastanawiam się, jaka jest wartość braku zainicjowania std::function
? Chciałbym pisać, if (eventFunc != nullptr)
ale std::function
(oczywiście) nie jest wskaźnikiem.
Dlaczego czysty, jeśli działa? Jaka magia się za tym kryje? I czy to właściwy sposób, jak to sprawdzić?
c++
c++11
std-function
NightElfik
źródło
źródło
eventFunc
to nie jest lambda; to jeststd::function
. Możesz przechowywać lambdy wstd::function
s, ale to nie to samo.Odpowiedzi:
Nie sprawdzasz, czy nie ma pustej lambdy, ale czy
std::function
ma ona zapisaną wartość docelową do wywołania . Sprawdzenie jest dobrze zdefiniowane i działa, dziękistd::function::operator bool
czemu umożliwia niejawną konwersję dobool
kontekstów, w których wymagane są wartości logiczne (takie jak wyrażenie warunkowe wif
instrukcji).Poza tym pojęcie pustej lambdy nie ma sensu. W tle kompilator konwertuje wyrażenie lambda na definicję
struct
(lubclass
), a przechwycone zmienne są przechowywane jako elementy składowe thisstruct
. Zdefiniowano również operator wywołania funkcji publicznej, co pozwala na wywołanie lambdy. Więc czym byłaby pusta lambda?Możesz także napisać,
if(eventFunc != nullptr)
jeśli chcesz, jest to odpowiednik kodu, który masz w pytaniu.std::function
definiujeoperator==
ioperator!=
przeciąża do porównywania znullptr_t
.źródło
== nullptr
Jednak nie robi tego samego? Wygląda na to==
, że operator powinien mieć przeciążenie , które powoduje „puste”std::function
porównanietrue
znullptr
: cplusplus.com/reference/functional/function/operatorsnullptr
will również zadziała,if(eventFunc != nullptr)
jest równoważneif(eventFunc)
w powyższym pytaniu.std::function::operator bool
nie zezwala na niejawną konwersję dobool
. Wexplicit
końcu jest zaznaczony , ale standard robi wyjątek dla pewnych konstrukcji językowych, które oczekują wyrażeń boolowskich, nazywając go „kontekstowo konwertowanym na bool”. Odpowiedni fragment koduexplicit
, dlatego uważałem, że zezwala na niejawną konwersję dobool
kontekstów, w których wymagane są wartości logiczne . Dokładnie to dzieje się w omawianym kodzie.Sprawdź tutaj http://www.cplusplus.com/reference/functional/function/operator_bool/
Przykład
// 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; }
Wynik
źródło
swap()
. Myślałem, że wynik jest wstecz, dopóki nie zdałem sobie z tego sprawy.(Pozwól, że udzielę jasnej odpowiedzi.)
Możesz sprawdzić, czy
std::function
jest pusty za pomocąstd::function::operator bool
.Przykład
#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; }
Wynik
źródło