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で正常にコンパイルされますが、eventFunc
を初期化せずにdoSomething()
を呼び出すと、コードが明らかにクラッシュします。それは予想されていましたが、eventFunc
の値は何だろうと思っていました。デバッガーは'empty'
と言います。そこで、単純なifステートメントを使用してそれを修正しました。
void doSomething() {
...
if (eventFunc) {
eventFunc(42);
}
}
これは機能しますが、初期化されていないstd::function
の値は何だと思いますか? if (eventFunc != nullptr)
と書きたいのですが、std::function
は(明らかに)ポインターではありません。
なぜ純粋なifが機能するのですか?その背後にある魔法は何ですか?そして、それを確認する正しい方法ですか?
空のラムダをチェックするのではなく、 std::function
に呼び出し可能なターゲットが格納されているかどうか。 std::function::operator bool
により、ブール値が必要なコンテキスト(bool
ステートメントの条件式など)でif
への暗黙的な変換が可能になるため、チェックは適切に定義され、機能します。
その上、空のラムダの概念は実際には意味をなしません。背後で、コンパイラはラムダ式をstruct
(またはclass
)定義に変換し、キャプチャした変数はこのstruct
のデータメンバーとして保存されます。パブリック関数呼び出し演算子も定義されています。これにより、ラムダを呼び出すことができます。それでは、空のラムダは何でしょうか?
必要に応じてif(eventFunc != nullptr)
と書くこともできます。これは、質問にあるコードと同等です。 std::function
定義operator==
およびoperator!=
と比較するためのnullptr_t
オーバーロード。
ここを確認してください 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は呼び出し不可能です。
バーは呼び出し可能です。