【问题标题】:How to properly check if std::function is empty in C++11?如何正确检查 C++11 中的 std::function 是否为空?
【发布时间】:2014-03-15 10:10:31
【问题描述】:

我想知道如何正确检查 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 有效?它背后的魔力是什么?而且,检查方法是否正确?

【问题讨论】:

  • 请注意,eventFunc 不是 lambda;这是std::function。您可以将 lambdas 存储在 std::functions 中,但它们不是一回事。
  • 你说得对,我改了标题以避免混淆。谢谢。

标签: c++ c++11 std-function


【解决方案1】:

您不是在检查空的 lambda,而是在 std::function 中是否存储了一个可调用的目标。由于std::function::operator bool 允许在需要布尔值的上下文(例如if 语句中的条件表达式)中隐式转换为bool,因此检查定义明确且有效。

此外,空 lambda 的概念并没有真正的意义。在幕后,编译器将 lambda 表达式转换为 struct(或 class)定义,您捕获的变量存储为此 struct 的数据成员。还定义了一个公共函数调用运算符,它允许您调用 lambda。那么空的 lambda 是什么?


如果你愿意,你也可以写if(eventFunc != nullptr),它相当于你在问题中的代码。 std::function defines operator==operator!= 重载用于与 nullptr_t 进行比较。

【讨论】:

  • == nullptr 不做同样的事情吗?看起来 == 运算符应该有一个重载,导致“空”std::functiontruenullptr 进行比较:cplusplus.com/reference/functional/function/operators
  • @KyleStrand 是的,与nullptr 相比也可以,if(eventFunc != nullptr) 相当于上述问题中的if(eventFunc)
  • 技术上,std::function::operator bool 不允许隐式转换为 bool。毕竟它被标记为explicit,但该标准对某些需要布尔表达式的语言结构做了一个例外,称其为“上下文转换为布尔值”。你可以在这里找到standardese的相关sn-p和解释:chris-sharpe.blogspot.com/2013/07/…
  • @bcrist 是的,我知道布尔转换运算符是explicit,这就是为什么我小心地声明允许在布尔值的上下文中隐式转换为bool需要。这正是相关代码中发生的情况。
  • @Praetorian 我想说的是,该标准为“隐式转换”这一短语赋予了非常具体的含义,它与“上下文转换为布尔”明显不同,后者也有非常具体的含义。这里没有“Is-a”关系。我知道初学者可能不需要马上知道隐式/显式/上下文转换之间的区别,但最好下意识地学习正确的单词,而不是以后必须打破旧习惯。
【解决方案2】:

在这里查看std::function::operator bool

返回值

  • 如果对象是可调用的,则为真。
  • 否则为假(对象为空函数)。

示例 Play with it online

// function::operator bool example
#include <iostream>     // std::cout
#include <functional>   // std::function, std::plus

int main ()
{
    std::function<int(int,int)> foo; // empty
    
    if(foo)
    {
        std::cout << "[1] foo is NOT empty" << std::endl;
    }
    else
    {
        std::cout << "[1] foo is EMPTY" << std::endl;
    }
    
    // Now we can assign example
    foo = std::plus<int>();
  
    if(foo)
    {
        std::cout << "[2] foo is NOT empty" << std::endl;
    }
    else
    {
        std::cout << "[2] foo is EMPTY" << std::endl;
    }
  
    // Example use with ternary operator (https://www.cprogramming.com/reference/operators/ternary-operator.html)
    std::cout << "[3] foo is " << (foo ? "callable" : "NOT callable") << std::endl;
    
    // make it empty
    foo = {};
    std::cout << "[4] foo is " << (foo ? "callable" : "NOT callable") << std::endl;
    
    foo = [](int a, int b){ return a+b; };
    std::cout << "[5] foo is " << (foo ? "callable" : "NOT callable") << std::endl;
    
    return foo(1, 1) == 2; // return 1
}

输出

[1] foo is EMPTY
[2] foo is NOT empty
[3] foo is callable
[4] foo is NOT callable
[5] foo is callable

【讨论】:

  • 我认为如果没有swap(),这个答案会更清楚。我一直以为输出是倒退的,直到我意识到这一点。
  • cplusplus.com 不是比cppreference.com 好很多吗?我真的发现前面的例子更清楚。为什么这么多人转向后者?我想知道!
【解决方案3】:

(让我提供一个明确的答案。)

您可以使用std::function::operator bool 检查std::function 是否为空。

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 不为空。
栏是空的。

【讨论】:

  • 你的结果字符串被交换了。
  • @Sophit 你确定吗? ;)
  • 您的评论说 foo 不是空的并且输出不同意。我同意你的评论。
猜你喜欢
  • 2017-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-09
  • 2012-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多