web-dev-qa-db-ja.com

C ++ 11でstd :: functionが空であるかどうかを適切にチェックするにはどうすればよいですか?

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が機能するのですか?その背後にある魔法は何ですか?そして、それを確認する正しい方法ですか?

87
NightElfik

空のラムダをチェックするのではなく、 std::function に呼び出し可能なターゲットが格納されているかどうか。 std::function::operator bool により、ブール値が必要なコンテキスト(boolステートメントの条件式など)でifへの暗黙的な変換が可能になるため、チェックは適切に定義され、機能します。

その上、空のラムダの概念は実際には意味をなしません。背後で、コンパイラはラムダ式をstruct(またはclass)定義に変換し、キャプチャした変数はこのstructのデータメンバーとして保存されます。パブリック関数呼び出し演算子も定義されています。これにより、ラムダを呼び出すことができます。それでは、空のラムダは何でしょうか?


必要に応じてif(eventFunc != nullptr)と書くこともできます。これは、質問にあるコードと同等です。 std::function定義operator==およびoperator!=と比較するためのnullptr_tオーバーロード。

91
Praetorian

ここを確認してください 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は呼び出し不可能です。

バーは呼び出し可能です。

19
Dawid Drozd