C++ std::function与std::invoke详解 | 可调用对象封装

C++ std::function与std::invoke:可调用对象的统一处理 #

引言 #

在C++中,std::function和std::invoke是两个处理可调用对象的重要工具,它们各自解决了不同的问题。

function与invoke的区别 #

std::functionstd::invoke 是C++中两个不同的概念,它们在功能和使用场景上存在明显差异。

std::function #

std::function 是一个函数对象的封装器,可以用来封装任意类型的可调用对象,比如函数指针、lambda表达式、函数对象等。通过 std::function,我们可以将不同类型的可调用对象统一成一种类型,便于存储和传递。

示例代码:

#include <functional>
#include <iostream>

void foo(int a, int b) {
    std::cout << "foo(" << a << ", " << b << ")" << std::endl;
}

int main() {
    // 将函数指针封装成 std::function 对象
    std::function<void(int, int)> f = foo;
    f(1, 2);
}

在上述代码中,我们将函数指针 foo 封装成了一个 std::function 对象 f,然后通过调用 f(1, 2) 来调用函数 foo

std::invoke #

std::invoke 是C++17标准引入的一个函数模板,用于调用可调用对象并返回结果。std::invoke 提供了统一的调用语法,无论可调用对象的类型是什么,都可以使用同一种方式进行调用。

示例代码:

#include <functional>
#include <iostream>

void foo(int a, int b) {
    std::cout << "a + b = " << a + b << std::endl;
}

class Bar {
public:
    void operator()(int a, int b) {
        std::cout << "a - b = " << a - b << std::endl;
    }
};

int main() {
    int a = 10, b = 5;
    // 调用普通函数
    std::invoke(foo, a, b);
    // 调用函数对象
    Bar bar;
    std::invoke(bar, a, b);
    // 调用成员函数
    std::invoke(&Bar::operator(), bar, a, b);
    // 调用 std::function 对象
    std::function<void(int, int)> f = foo;
    std::invoke(f, a, b);
}

在C++17之前,调用不同类型的可调用对象需要使用不同的语法,比如直接调用函数、使用类对象的运算符重载操作符()来调用函数对象、使用成员函数指针来调用类成员函数等等。而 std::invoke 解决了这种不一致的问题,提供了一种通用的调用方式。

function与invoke的区别 #

  • 功能不同std::function 用于封装可调用对象,将其转换为一种统一的函数对象类型;而 std::invoke 用于调用可调用对象,提供了一种通用的调用语法。
  • 使用场景不同std::function 适用于需要存储和传递可调用对象的场景;std::invoke 则适用于需要统一调用各种不同类型可调用对象的场景。

总结来说,std::functionstd::invoke 在C++中的作用和使用场景是不同的,它们各自解决了不同的问题。理解它们的区别有助于在实际开发中正确选择和使用这些工具。