Je me demandais comment vérifier correctement si un std::function
Est vide. Considérons cet exemple:
class Test {
std::function<void(int a)> eventFunc;
void registerEvent(std::function<void(int a)> e) {
eventFunc = e;
}
void doSomething() {
...
eventFunc(42);
}
};
Ce code se compile parfaitement dans MSVC mais si j'appelle doSomething()
sans initialiser le eventFunc
, le code se bloque évidemment. C'est prévu, mais je me demandais quelle est la valeur de eventFunc
? Le débogueur dit 'empty'
. J'ai donc corrigé cela en utilisant une simple déclaration if:
void doSomething() {
...
if (eventFunc) {
eventFunc(42);
}
}
Cela fonctionne mais je me demande toujours quelle est la valeur de std::function
Non initialisé? J'aimerais écrire if (eventFunc != nullptr)
mais std::function
N'est (évidemment) pas un pointeur.
Pourquoi le pur si fonctionne? Quelle est la magie derrière tout ça? Et, est-ce la bonne façon de vérifier?
Vous ne recherchez pas un lambda vide, mais vérifiez si std::function
contient une cible appelable. La vérification est bien définie et fonctionne à cause de std::function::operator bool
qui permet la conversion implicite en bool
dans des contextes dans lesquels des valeurs booléennes sont requises (telle que l'expression conditionnelle dans une déclaration if
).
En outre, la notion de lambda vide n'a pas vraiment de sens. En coulisse, le compilateur convertit une expression lambda en une définition de struct
(ou class
), les variables que vous capturez étant stockées en tant que membres de données de ce struct
. Un opérateur d'appel de fonction publique est également défini, ce qui vous permet d'appeler le lambda. Alors, quel serait un lambda vide?
Vous pouvez également écrire if(eventFunc != nullptr)
si vous le souhaitez, cela équivaut au code que vous avez dans la question. std::function
définitoperator==
Et operator!=
Surchargent pour permettre la comparaison avec un nullptr_t
.
Vérifiez ici http://www.cplusplus.com/reference/functional/function/operator_bool/
Exemple
// 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;
}
Sortie
foo n'est pas appelable.
bar est appelable.