仿函数 – STL 基础

最近更新于 2024-05-05 14:18

环境

Debian 11(arm64)

编译器 g++ 10.2.1;编译标准 C++20;参数:-std=c++20 -no-pie -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Werror=format-security -Wextra -pedantic -Wimplicit-fallthrough -Wsequence-point -Wswitch-unreachable -Wswitch-enum -Wstringop-truncation -Wbool-compare -Wtautological-compare -Wfloat-equal -Wshadow=global -Wpointer-arith -Wpointer-compare -Wcast-align -Wcast-qual -Wwrite-strings -Wdangling-else -Wlogical-op -Wconversion -g -O0

仿函数

在前面面向对象基础部分也提过仿函数(https://blog.iyatt.com/?p=9028 ),仿函数实质上就是对 () 小括号进行重载,也被称为函数对象

基础使用

#include <iostream>

class Add
{
    private:
        int m_num1, m_num2;

    public:
        int m_result;
        int flag; // true 加数从仿函数传入;false 加数通过构造函数传入

        // 默认构造
        Add()
        {
            flag = true;
        }

        // 构造执行初始化
        Add(int num1, int num2) : m_num1(num1), m_num2(num2)
        {
            flag = false;
        }

        // 重载 (),即仿函数
        int operator()(int num1 = 0, int num2 = 0)
        {
            if (flag)
            {
                m_num1 = num1;
                m_num2 = num2;
            }
            m_result = m_num1 + m_num2;
            return m_result;
        }
};

void test1(int num1, int num2, Add add)
{
    std::cout << add(num1, num2) << std::endl;
}

void test2(Add add)
{
    std::cout << add() << std::endl;
}

int main()
{
    Add add1; // 实例化 1
    int result = add1(9, 1); // 执行仿函数,可以通过返回值获取结果
    std::cout << result << std::endl;

    Add add2(1, 9); // 实例化 2
    add2(); // 执行仿函数
    std::cout << add2.m_result << std::endl; // 通过成员变量获取结果

    // 匿名对象的应用,不实例化创建名字,直接使用类名创建一个临时对象
    // 第一対括号创建匿名对象,调用构造函数初始化,第二对括号调用仿函数执行
    std::cout << Add(15, 5)() << std::endl;
    // 第一对括号时调用的默认构造函数,第二对括号调用仿函数并传入参数
    std::cout << Add()(15, 5) << std::endl;

    // 函数对象的应用
    // Add 就是函数对象
    test1(15, 15, Add());
    test2(Add(15, 15));
}

file

谓词

返回值为 bool 的仿函数

#include <iostream>
#include <vector>

class Filter
{
    public:
        // 接受一个参数,一元谓词
        bool operator()(int num)
        {
            if (num > 5)
            {
                return true;
            }
            return false;
        }
};

int main()
{
    std::vector<long> v1;
    for (int i = 0; i < 10; ++i)
    {
        v1.push_back(random() % 10);
    }

    for (long i : v1)
    {
        std::cout << i << " ";
    }
    std::cout << std::endl;

    // 寻找第一个大于 5 的数
    // 一元谓词使用
    std::vector<long>::const_iterator it = std::find_if(v1.begin(), v1.end(), Filter());
    if (it != v1.end())
    {
        std::cout << *it << std::endl;
    }
}

file

#include <iostream>
#include <vector>
#include <algorithm>

class Reverse
{
    public:
        bool operator()(int num1, int num2) // 二元谓词
        {
            if (num1 > num2)
            {
                return true;
            }
            return false;
        }
};

void print(const std::vector<long> v)
{
    for (long i : v)
    {
        std::cout << i << " ";
    }
    std::cout << std::endl;
}

int main()
{
    std::vector<long> v1;
    for (int i = 0; i < 10; ++i)
    {
        v1.push_back(random() % 10);
    }
    print(v1);

    std::sort(v1.begin(), v1.end()); // 排序,默认升序
    print(v1);

    std::sort(v1.begin(), v1.end(), Reverse()); // 降序排序 - 二元谓词使用
    print(v1);
}

file

内建仿函数

C++ 内部已经定义好了一些仿函数,使用需要包含头文件 functional

算数

算数运算

#include <iostream>
#include <functional>

int main()
{
    std::plus<std::string> plus; // 加
    std::string s1, s2;
    s1 = "abc";
    s2 = "123";
    std::cout << plus(s1, s2) << std::endl;

    std::cout << std::minus<int>()(10, 6) << std::endl; // 减
    std::cout << std::multiplies<double>()(4.5, 2) << std::endl; // 乘
    std::cout << std::divides<int>()(10, 5) << std::endl; // 除
    std::cout << std::negate<int>()(43) << std::endl; // 相反数
    std::cout << std::modulus<int>()(10, 4) << std::endl; // 取模
}

file

关系

比较运算

#include <iostream>
#include <functional>

int main()
{
    std::cout << std::equal_to<std::string>()("abc", "123") << std::endl; // 等于
    std::cout << std::not_equal_to<std::string>()("abc", "123") << std::endl; // 不等于
    std::cout << std::less<int>()(10, 20) << std::endl; // 小于
    std::cout << std::less_equal<int>()(10, 10) << std::endl; // 小于等于
    std::cout << std::greater<int>()(10, 20) << std::endl; // 大于
    std::cout << std::greater_equal<int>()(10, 20) << std::endl; // 大于等于
}

file

逻辑

逻辑运算

#include <iostream>
#include <functional>

int main()
{
     // 逻辑与
    std::cout << std::logical_and<bool>()(true, true) << std::endl;
    std::cout << std::logical_and<bool>()(true, false) << std::endl;
    std::cout << std::logical_and<bool>()(false, false) << std::endl;

    // 逻辑或
    std::cout << std::logical_or<bool>()(true, true) << std::endl;
    std::cout << std::logical_or<bool>()(true, false) << std::endl;
    std::cout << std::logical_or<bool>()(false, false) << std::endl;

    // 逻辑非
    std::cout << std::logical_not<bool>()(true) << std::endl;
    std::cout << std::logical_not<bool>()(false) << std::endl;
}

file

位运算

#include <iostream>
#include <functional>

int main()
{
    // 10 二进制是 10010,8 二进制是是 10000

    std::cout << std::bit_and<int>()(10, 8) << std::endl; // 按位与
    std::cout << std::bit_or<int>()(10, 8) << std::endl; // 按位或
    std::cout << std::bit_xor<int>()(10, 8) << std::endl; // 按位异或
    std::cout << std::bit_not<unsigned>()(10) << std::endl; // 按位取反
}

file

哈希

用于将数据类型转换为哈希值,用于支持哈希表等数据结构

#include <iostream>
#include <functional>

int main()
{
    std::cout << std::hash<const char *>()("Hello world") << std::endl;

    std::hash<const char *> hash;
    std::cout << hash("hello world") << std::endl;
}

file

函数适配器

用于对已有的仿函数进行修改,使其满足特定的需求

// 绑定函数和一部分参数
#include <functional>
#include <iostream>

void f(std::string s1, std::string s2, std::string s3)
{
    std::cout << s1 << " " << s2 << " " << s3 << std::endl;
}

int main()
{
    // f 需要传入 3 个参数,这里适配成两个参数已经指定,只需传入一个参数的 ff
    auto ff = std::bind(f, "hello", std::placeholders::_1, "world");
    ff("你好");

    // std::placeholders 是占位符,必须从 _1 开始编号,用于适配后的函数传入参数
    auto fff = std::bind(f, "123", std::placeholders::_1, std::placeholders::_2);
    fff("你好", "世界");
}

file

// 函数封装(普通函数、成员函数和 Lambda 表达式)
#include <iostream>
#include <functional>

void fun1()
{
    std::cout << "fun1" << std::endl;
}

int fun2(int num1, int num2)
{
    return num1 * num2;
}

class Fun3
{
    public:
        int fun(int num1, int num2)
        {
            return num1 + num2;
        }
};

int main()
{
    // 普通函数
    std::function<void()> f1 = fun1;
    f1();

    std::function<int(int, int)> f2 = fun2;
    std::cout << f2(3, 4) << std::endl;

    // 成员函数
    Fun3 fun3;
    std::function<int(Fun3&, int, int)> f3 = &Fun3::fun;
    std::cout << f3(fun3, 7, 3) << std::endl;

    // Lambda 表达式
    std::function<void()> f4 = [](){std::cout << "Lambda" << std::endl;};
    f4();
}

file

补充:Lambda 表达式可参考 https://blog.iyatt.com/?p=9503

仿函数 – STL 基础
Scroll to top