C ++ 11でstd :: functionが空かどうかを適切に確認する方法


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これはラムダではないことに注意してください。それはstd::functionです。ラムダをstd::functionsに格納できますが、同じものではありません。
templatetypedef

3
正解です。混乱を避けるためにタイトルを変更しました。ありがとう。
NightElfik 2014

回答:


104

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

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


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


1
== nullptr同じことをしませんか?以下のために過負荷があるようになっているように見えます==「空」の原因となるオペレータstd::function比較することをtrue反対nullptrcplusplus.com/reference/functional/function/operators
カイルストランド

3
@KyleStrandはい、比較してnullptrも機能しますが、上記の質問if(eventFunc != nullptr)と同等if(eventFunc)です。
Praetorian

3
技術的にstd::function::operator boolは、への暗黙の変換は許可されていませんbool。それはexplicit結局マークされていますが、標準はブール式を期待する特定の言語構成を例外とし、それを「文脈的にブールに変換された」と呼びます。あなたはここにstandardeseの関連するスニペットと説明を見つけることができます:chris-sharpe.blogspot.com/2013/07/...
bcrist

@bcristはい、ブール変換演算子がそうexplicitであることを知っています。そのためbool、ブール値が必要なコンテキストで暗黙的な変換ができるように注意して述べたのはこのためです。これはまさに問題のコードで起こっていることです。
Praetorian

5
@Praetorian私が主張しようとしている点は、標準が「暗黙の変換」という語句に非常に具体的な意味を割り当てており、これも非常に具体的な意味を持つ「コンテキストによるブールへの変換」とは明らかに異なることです。ここには「Is-a」関係はありません。初心者はおそらく暗黙的/明示的/文脈的変換の違いをすぐに知る必要がないと思いますが、後で古い習慣を破る必要はなく、無意識のうちに正しい単語を学ぶ方が良いでしょう。
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で空かどうかを確認でき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
結果の文字列が交換されます。
ソフィット

@ソフィットよろしいですか?;)
zwcloud

1
あなたのコメントはfooは空ではなく、出力は同意しないと言っています。あなたのコメントに同意します。
ソフィット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.