1月上旬:《C++STL》读书笔记----STL仿函数

is_sorted 检查区间元素是否按升序排列 
sort 将区间按升序排序 
partial_sort   将区间内较小的N个元素排序 
stable_sort    将区间内的元素排序,同时保持相等的元素之间的顺序 


二分搜索操作(在已排序范围上)
lower_bound 返回指向第一个不小于给定值的元素的迭代器 
upper_bound  返回指向第一个大于给定值的元素的迭代器
binary_search 判断一个元素是否在区间内 


集合操作(在已排序范围上)
merge  合并两个已排序的区间
includes 如果一个集合是另外一个集合的子集则返回true 
set_difference 计算两个集合的差集 
set_intersection 计算两个集合的交集 


堆操作
is_heap 检查给定的区间是否为一个堆 
make_heap 根据区间内的元素创建出一个堆 
push_heap 将元素加入到堆 
pop_heap 将堆中的最大元素删除 


最小/最大操作
max(min) 返回两个元素中的较大者(较小者)
max_element(min_element)  返回区间内的最小元素 
lexicographical_compare 如果按字典顺序一个区间小于另一个区间,返回true 
is_permutation 判断一个序列是否为另一个序列的排列组合 
next_permutation(prev_permutation)     按字典顺序产生区间内元素下一个较大(小)的排列组合 


常用的比较函数
less              #小于(缺省比较函数)  
greater           #大于  
equal_to          #等于  
less_equal        #小于等于  
greater_equal     #大于等于  


容器中值的数值运算
iota  (C++11) 用从起始值开始连续递增的值填充区间 
accumulate 计算区间内元素的和 
inner_product 计算两个区间元素的内积 


adjacent_difference 计算区间内相邻元素之间的差 
// 默认实现—两个个项之间的差
std::vector<int> v{2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
std::adjacent_difference(v.begin(), v.end(), v.begin()); // 第一个2来自v[0],其他都是逐项差,{2,2,2,2,2,2,2}


gcd(C++17) 返回两个整数最大公约数的 
lcm(C++17) 返回两个整数最小公倍数的 




函数对象、函数调用、绑定操作、引用包装
何谓函数对象?
重载函数调用操作符(operator () )的类或结构体,其对象常称为函数对象(function object),即它们是行为类似函数的对象。又称仿函数。函数对象是支持operator()函数调用运算符的任意对象
“在标准库中,函数对象被广泛地使用以获得弹性”


定义了许多函数对象类型和支持函数对象的功能,。

std::function   该类模板是通用多态函数封装器。std::function 的实例能存储、复制及调用任何可调用 (Callable) 目标——函数、 lambda 表达式、 bind 表达式或其他函数对象,还有指向成员函数指针和指向数据成员指针。

void print_num(int i)
{
    std::cout << i << '\n';
}
struct PrintNum {
    void operator()(int i) const
    {
        std::cout << i << '\n';
    }
};
int main()
{
    // 存储自由函数
    std::function<void(int)> f_display = print_num;
    f_display(-9);
 
	// 存储 lambda
    std::function<void()> f_display_42 = []() { print_num(42); };
    f_display_42();
	
	// 存储到 std::bind 调用的结果
    std::function<void()> f_display_31337 = std::bind(print_num, 31337);
    f_display_31337();
	
	// 存储到函数对象的调用
    std::function<void(int)> f_display_obj = PrintNum();
    f_display_obj(18);
}
std::placeholders::_1  .....   std::placeholders::_N
于 std::bind 表达式用作参数时,占位符对象被存储于生成的函数对象,而以未绑定参数调用函数对象时,每个占位符 _N 被对应的第 N 个未绑定参数替换。

下列代码展示以占位符参数创建函数对象:

#include <functional>
#include <string>
#include <iostream>
 
void goodbye(const std::string& s)
{
    std::cout << "Goodbye " << s << '\n';
}
 
class Object {
public:
    void hello(const std::string& s)
    {
        std::cout << "Hello " << s << '\n';
    }
};
 
int main(int argc, char* argv[])
{
    typedef std::function<void(const std::string&)> ExampleFunction;
    Object instance;
    std::string str("World");
    ExampleFunction f = std::bind(&Object::hello, &instance, 
                                  std::placeholders::_1);
 
    // 等价于 instance.hello(str)
    f(str);
    f = std::bind(&goodbye, std::placeholders::_1);
 
    // 等价于 goodbye(str)
    f(str);    
    return 0;
}
为什么需要右值引用?


std:: ref  : 需要被包装的到对象的左值引用

示例代码:

#include <functional>
#include <iostream>
void f(int& n1, int& n2, const int& n3)
{
    std::cout << "In function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
    ++n1; // 增加存储于函数对象的 n1 副本
    ++n2; // 增加 main() 的 n2
    // ++n3; // 编译错误
}
 
int main()
{
    int n1 = 1, n2 = 2, n3 = 3;
    std::function<void()> bound_f = std::bind(f, n1, std::ref(n2), std::cref(n3));
    n1 = 10;
    n2 = 11;
    n3 = 12;
    std::cout << "Before function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
    bound_f();
    std::cout << "After function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
}

std::bind: 函数模板 bind 生成 类f 的转发调用包装器。调用此包装器等价于以一些绑定到 args 的参数调用 f 

#include <random>
#include <iostream>
#include <memory>
#include <functional>
 
void f(int n1, int n2, int n3, const int& n4, int n5)
{
    std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}
 
int g(int n1)
{
    return n1;
}
 
struct Foo {
    void print_sum(int n1, int n2)
    {
        std::cout << n1+n2 << '\n';
    }
    int data = 10;
};
 
int main()
{
    using namespace std::placeholders;  // 对于 _1, _2, _3...
 
    // 演示参数重排序和按引用传递
    int n = 7;
    // ( _1 与 _2 来自 std::placeholders ,并表示将来会传递给 f1 的参数)
    auto f1 = std::bind(f, _2, _1, 42, std::cref(n), n);
    n = 10;
    f1(1, 2, 1001); // 1 为 _1 所绑定, 2 为 _2 所绑定,不使用 1001
                    // 进行到 f(2, 1, 42, n, 7) 的调用
    //2 1 42 10 7
	
    // 嵌套 bind 子表达式共享占位符
    auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
    f2(10, 11, 12); // 进行到 f(12, g(12), 12, 4, 5); 的调用
    //12 12 12 4 5
 
    // 绑定指向成员函数指针
    Foo foo;
    auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f3(5);   //100
 
    // 绑定指向数据成员指针
    auto f4 = std::bind(&Foo::data, _1);
    std::cout << f4(foo) << '\n';   //10
}

还有一些关于运算的函数对象:

int num = std::plus<int>()(5, 6);   //11
num = std::modulus<int>()(4, 6); //取模 4
num =  std::negate<int>()(4);  //取相反数 -4

bool smaller = std::less<int>()(5, 6); //true
smaller = std::greater_equal<int>()(5, 6); //true

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值