C++11 std::function

本文详细介绍了C++标准库中的std::function类模板,包括其通用性和多态性的特点,通过具体示例展示了如何使用std::function来存储、复制和调用不同类型的可调用对象,如普通函数、lambda表达式、成员函数、成员变量及仿函数等。

一 定义

头文件<funticonal>

先来看一段话

Class template std::function is a general-purpose polymorphic function wrapper. Instances of std::function can store, copy, and invoke any Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.

 类模板 std::function 是通用多态函数封装器。可以存储普通函数、lambda表达式、类成员函数、类成员变量、仿函数等。

二 举例

#include <iostream>
#include <functional>

// 类
struct Demo
{
    void print(int a, int b)
    {
        std::cout << "Demo " << a << " " << b << " " << a_ << std::endl;
    };
    int a_ = 1;
};

// 普通函数
int add(int& a, int& b)
{
    a++;
    b++;
    std::cout << "add " << a << " " << b << std::endl;
    return a + b;
}

// 仿函数
struct PrintDemo
{
    void operator()(int i) const
    {
        std::cout << "PrintDemo " << i << std::endl;
    }
};

int main()
{
    using namespace std::placeholders;

    {
        int a = 1;
        int b = 2;
        // 1、存储普通函数
        std::function<int(int&, int&)> f = add; // 方式1
        // std::function<int(int&, int&)> f = std::bind(add, _1, _2); // 方式2

        f(a, b); // output: add 2 3
    }

    {
        // 2、绑定lambda
        std::function<void()> f = []()
		{
            std::cout << "hello" << std::endl;
        };
    }

    {
        Demo demo;
        // 3、存储成员函数
        std::function<void(Demo&, int, int)> f1 = &Demo::print; // 方式1
        // std::function<void(int, int)> f1 = std::bind(&Demo::print, &demo, _1, 10); // 方式2

        // 4、存储成员变量
        std::function<int(Demo&)> f2 = &Demo::a_; // 方式1
        // std::function<int(Demo&, int)> f2 = std::bind(&Demo::a_, _1); // 方式2

        f1(demo, 10, 20); // output: Demo 10 20 1
        std::cout << f2(demo); // output: 1
    }
    {
        // 5、存储仿函数
        std::function<void(int)> f = PrintDemo();
        f(100); // output: PrintDemo 100
    }
    system("pause");
    return 0;
}

三、注意点

1、std::function 和std::bind的头文件均是<functional>,查看 std::bind

2、std::function实现了一套类型消除机制,可以统一处理不同的函数对象类型。以前我们使用函数指针,现在我们可以使用std::function来完成。

C++11引入了`std::function`作为通用的函数对象封装器,极大地增强了函数对象的灵活性和通用性。然而,尽管其设计和实现经过了标准化,但在实际使用过程中仍然存在一些已知问题或缺陷。 首先,`std::function`在某些情况下可能会导致性能问题。由于`std::function`内部使用了类型擦除技术,它需要进行动态内存分配来存储可调用对象。这种动态分配在某些高性能场景下可能成为瓶颈。此外,调用`std::function`对象时需要进行间接跳转,这可能会导致CPU分支预测失败,从而影响执行效率[^1]。 其次,`std::function`的拷贝语义有时可能会引起误解。虽然`std::function`支持拷贝构造和赋值操作,但这些操作可能会抛出异常,特别是在内部需要进行动态内存分配的情况下。因此,在要求异常安全的代码中使用`std::function`时需要格外小心。 另外,`std::function`在处理具有重载操作符的函数对象时可能会遇到问题。例如,当一个类定义了多个`operator()`时,`std::function`无法自动推导出应该使用哪一个,这会导致编译错误。为了避免这种情况,通常需要显式指定目标函数的类型或使用lambda表达式进行包装。 还有,`std::function`在某些编译器实现中可能存在兼容性问题。例如,某些旧版本的编译器可能没有完全实现`std::function`的所有特性,或者在特定平台上的表现与标准不符。因此,在跨平台开发时需要特别注意编译器的支持情况。 最后,`std::function`的类型信息在运行时会被擦除,这意味着在调试时很难直接从`std::function`对象中获取其内部封装的具体函数信息。这对于调试和日志记录来说是一个挑战。 ### 示例代码 以下是一个简单的示例,展示了如何使用`std::function`来封装不同的可调用对象: ```cpp #include <iostream> #include <functional> void foo(int x) { std::cout << "foo: " << x << std::endl; } struct Bar { void operator()(int x) const { std::cout << "Bar: " << x << std::endl; } }; int main() { std::function<void(int)> func; // 封装普通函数 func = foo; func(10); // 封装函数对象 Bar bar; func = bar; func(20); return 0; } ``` ### 相关问题 1. `std::function`在多线程环境中使用时需要注意哪些问题? 2. 如何避免`std::function`在高性能场景下的性能瓶颈? 3. `std::function`的异常安全性如何保证? 4. 在哪些情况下`std::function`无法正确推导出可调用对象的类型? 5. 如何在调试时获取`std::function`内部封装的具体函数信息? : 由于`std::function`的实现依赖于类型擦除技术,因此在某些情况下可能会导致额外的性能开销。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值