0Pricing
C++ Academy · 课时

std::function

存储任意可调用对象

std::function 是 CoddyKit 上的免费 C++ Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C++ Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C++ Academy 课程共包含 4 节课。

什么是 std::function

std::function 是一种类型擦除包装器,可以容纳与给定签名匹配的任何可调用对象:普通函数、lambda 表达式、函子或绑定表达式。

  • 使用目标签名声明。
  • 位于 <functional> 中。
#include <iostream>
#include <functional>

int add(int a, int b) { return a + b; }

int main() {
    std::function<int(int, int)> f = add;
    std::cout << f(2, 3) << '\n';
    return 0;
}

存储 lambda 表达式

与原始函数指针不同,std::function 可以轻松存储 lambda 表达式,即使该表达式带有捕获也没问题。

#include <iostream>
#include <functional>

int main() {
    int offset = 10;
    std::function<int(int)> f = [offset](int x) { return x + offset; };
    std::cout << f(5) << '\n';
    return 0;
}

存储函子

函子是一个包含 operator() 的对象。std::function 可以包装函子,并在被调用时调用它的运算符。

#include <iostream>
#include <functional>

struct Multiplier {
    int factor;
    int operator()(int x) const { return x * factor; }
};

int main() {
    std::function<int(int)> f = Multiplier{3};
    std::cout << f(4) << '\n';
    return 0;
}

重新分配目标

在其生命周期内,一个 std::function 变量可以指向不同的可调用对象,这对于在运行时切换行为很有用。

#include <iostream>
#include <functional>

int main() {
    std::function<int(int)> f = [](int x) { return x + 1; };
    std::cout << f(10) << '\n';
    f = [](int x) { return x * x; };
    std::cout << f(10) << '\n';
    return 0;
}

空的 std::function

默认构造的 std::function 不包含任何内容。调用它会抛出 std::bad_function_call,因此请先进行测试。

#include <iostream>
#include <functional>

int main() {
    std::function<void()> f;
    if (f) {
        f();
    } else {
        std::cout << "empty\n";
    }
    return 0;
}

作为参数

函数可以接收 std::function 参数,以接受任何匹配的可调用对象,从而使应用程序接口更加灵活。

#include <iostream>
#include <functional>

void repeat(int n, const std::function<void(int)>& action) {
    for (int i = 0; i < n; ++i) action(i);
}

int main() {
    repeat(3, [](int i) { std::cout << "step " << i << '\n'; });
    return 0;
}

存储回调函数

一种常见用法是将回调函数保存在类成员中,以便事件发生时稍后调用它。

#include <iostream>
#include <functional>

struct Button {
    std::function<void()> onClick;
    void click() { if (onClick) onClick(); }
};

int main() {
    Button b;
    b.onClick = [] { std::cout << "clicked!\n"; };
    b.click();
    return 0;
}

可调用对象的向量

由于它们共享同一种类型,不同的可调用对象可以共同存放在容器中,并依次被调用。

#include <iostream>
#include <functional>
#include <vector>

int inc(int x) { return x + 1; }

int main() {
    std::vector<std::function<int(int)>> ops;
    ops.push_back(inc);
    ops.push_back([](int x) { return x * 2; });
    for (auto& op : ops) std::cout << op(10) << ' ';
    std::cout << '\n';
    return 0;
}

类型擦除的代价

std::function 可能会分配内存,并会增加一次间接调用,因此它的速度略慢于直接调用或使用模板的可调用对象。需要统一存储时再使用它。

#include <iostream>
#include <functional>

int main() {
    std::function<int()> f = [] { return 42; };
    int total = 0;
    for (int i = 0; i < 5; ++i) total += f();
    std::cout << total << '\n';
    return 0;
}

返回 std::function

工厂函数可以构建并返回一个经过配置的可调用对象,让调用者获得自定义行为。

#include <iostream>
#include <functional>

std::function<int(int)> adder(int n) {
    return [n](int x) { return x + n; };
}

int main() {
    auto add5 = adder(5);
    std::cout << add5(10) << '\n';
    return 0;
}

与函数指针对比

std::function 比函数指针更灵活,因为它可以存储状态,但这种灵活性会带来少量性能开销,并且可能发生内存分配。

#include <iostream>
#include <functional>

int main() {
    int base = 7;
    std::function<int(int)> stateful = [base](int x) { return x + base; };
    std::cout << "Stateful result: " << stateful(3) << '\n';
    return 0;
}

快速检查

测试您对 std::function 的理解。

回顾

您了解到 std::function:

  • 包装任何与其签名匹配的可调用对象,包括有状态的 lambda 表达式和函子
  • 可以重新赋值、存储在容器中,以及从工厂函数返回
  • 为空时会抛出 bad_function_call
  • 会因类型擦除产生少量额外开销

接下来,您将使用 std::bind 预先填充可调用对象的参数。

常见问题解答

「std::function」课时是免费的吗?

是的 — 「std::function」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C++ Academy 课程的其余内容,请升级到 CoddyKit PRO。 C++ Academy 课程共包含 4 节课。

「std::function」这节课中我会学到什么?

存储任意可调用对象 你通过在浏览器中直接运行的动手代码来练习 C++ Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C++ Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C++ Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「std::function」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C++ Academy 课中编写并运行代码吗?

能。每节 C++ Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 函数指针
  2. std::function
  3. std::bind
  4. 选择可调用对象
← 返回 C++ Academy