boost库学习:函数对象

介绍

函数对象又称高阶函数,是一组重载的函数模板,用来向一个函数(或函数对象)绑定某些参数. 

实际使用中可以作为参数传递给另一个函数,或者作为某函数的返回值的一类函数。

Boost.Bind

源码

boost/bind.hpp

简单使用

一元函数

#include <boost/bind.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void print(const int num)
{
  cout << num <<endl;
}

int main()
{
  std::vector<int> v;
  v.push_back(1);
  v.push_back(2);
  v.push_back(3);

  std::for_each(v.begin(), v.end(), print);
  std::for_each(v.begin(), v.end(), boost::bind(print, _1)); // 和上一行输出一样,相当于对vector的每个元素x调用 boost::bind(print, _1)(x)
  for (size_t index = 0; index < v.size(); index++)
  {
    boost::bind(print, _1)(v[index]);                                                                                                    
  }
}

二元函数(只提供一个参数)

#include <boost/bind.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void print(const int a, const int b)
{
  cout << a << " " << b << endl;
}

void print3(const int a, const int b, const int c)
{
  cout << a << " " << b << " " << c << endl;
}

int main()
{
  std::vector<int> v;
  v.push_back(1);
  v.push_back(2);
  v.push_back(3);

  std::for_each(v.begin(), v.end(), boost::bind(print, 10, _1)); // 相当于对vector的每个元素x调用 print(10, x),用x取代占位符_1
  std::for_each(v.begin(), v.end(), boost::bind(print, _1, 10)); // 相当于对vector的每个元素x调用 print(x, 10),用x取代占位符_1
  for (size_t index = 0; index < v.size(); index++)
  {
    boost::bind(print, 10, _1)(v[index]);
  }

  std::for_each(v.begin(), v.end(), boost::bind(print3, 11, _1, 33)); // 相当于对vector的每个元素x调用 print3(11, x, 33),用x取代占位符_1
  std::for_each(v.begin(), v.end(), boost::bind(print3, _1, 22, 33)); // 相当于对vector的每个元素x调用 print3(x, 22, 33),用x取代占位符_1 
  for (size_t index = 0; index < v.size(); index++)
  {
    boost::bind(print3, 44, _1, _2)(v[index], 55);
  }
}

二元函数(提供两个参数)

#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;

bool compare(int i, int j)
{
  return i > j;
}

int main()
{
  std::vector<int> v;
  v.push_back(1);
  v.push_back(2);
  v.push_back(3);

  // sort 根据第三个参数func 返回值判断顺序, true 表示x1 在x2前面
  std::sort(v.begin(), v.end(), boost::bind(compare, _1, _2)); // func(x1, x2) => boost::bind(compare, _1, _2))(x1, x2) => compare(x1, x2),当x1 > x2 时返回true,所以从大到小排序
  //std::sort(v.begin(), v.end(), compare); 
  for (size_t i = 0; i < v.size(); i++)
  {
    cout << v[i] <<endl;
  }

  //std::sort(v.begin(), v.end(), boost::bind(compare, _2, _2));  // 相当于compare(x2, x2) 元素自己比较,不会改变顺序
  std::sort(v.begin(), v.end(), boost::bind(compare, _2, _1)); // func(x1, x2) => boost::bind(compare, _2, _1))(x1, x2) => compare(x2, x1),当x2 > x1 时返回true,所以从小到大排序 
  for (size_t i = 0; i < v.size(); i++)
  {
    cout << v[i] <<endl;
  }
}

Boost.Ref

通常与 Boost.Bind 一起使用

提供了两个函数 - boost::ref() 和 boost::cref() - 定义于 boost/ref.hpp

如果bind 的函数有引用类型的参数,那么需要Boost.Ref 来对该位置参数特殊处理,因为 boost::bind 会复制它的参数。

简单使用

#include <boost/bind.hpp>
#include <iostream>
#include <vector>
#include <algorithm>

void add(int i, int j, std::ostream &os)
{
  os << i + j << std::endl;
}

int main()
{
  std::vector<int> v;
  v.push_back(1);
  v.push_back(3);
  v.push_back(2);

  std::for_each(v.begin(), v.end(), boost::bind(add, 10, _1, boost::ref(std::cout)));                                                                                            
  //std::for_each(v.begin(), v.end(), boost::bind(add, 10, _1, std::cout));  // 错误,因为标准输出对象继承自 'std::ios_base',而这个类的拷贝构造函数是私有的,意味着不允许对std::
cout进行拷贝
}

如果执行上述代码被注释的部分会出错,因为boost::bind 会尝试对std::cout 进行拷贝,但 标准输出对象继承自 'std::ios_base',而这个类的拷贝构造函数是私有的,意味着不允许对std:: cout进行拷贝

Boost.Function

用于封装函数指针, 源码位于:boost/function.hpp

简单使用

#include <boost/function.hpp>
#include <iostream>
using namespace std;

void print(int num)
{
  cout << num << endl;
}
void printAddOne(int num)
{
  cout << num + 1 << endl;
}

int main()
{
    boost::function<void (int)> f;
    f = print;
    f(10);
    f = printAddOne;
    f(10);                                
}

如上定义了一个指向“参数为int,返回void的函数”的函数指针f。通过用符合条件的函数对其赋值,然后将其作为函数般调用。

如果 f 未赋予一个函数而被调用,则会抛出一个 boost::bad_function_call 异常。

#include <boost/function.hpp>
#include <iostream>
using namespace std;

int main()
{
    boost::function<void (int)> f;
    try
    {
      if (f.empty())
      {
        cout << "f is empty" << endl;
      }
      if (!f) // operator bool()
      {
        cout << "f is null" << endl;
      }
      f(1);                                
    }
    catch(boost::bad_function_call& e)
    {
      cout << e.what() << endl;
    }
}

输出:

f is empty
f is null
call to empty boost::function

绑定类成员函数

#include <boost/function.hpp>
#include <iostream>
using namespace std;

class A
{
  public:
    void print(std::ostream& os)
    {
      os << "success" << endl;
    }
};

int main()
{
    boost::function<void (A*, std::ostream&)> f;
    A a;
    f = &A::print;
    f(&a, boost::ref(std::cout));                 
}

对于这种定义,函数指针模板的第一个参数必须是成员函数所属类的指针类型,后面是函数的参数列表。因为要传递std::cout 的引用,所以用了boost::ref。

Boost.Lambda

用简洁的语法表达一个函数,令源代码更为紧凑

简单使用

#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/lambda/if.hpp>

void print(int i)
{
  std::cout << i << std::endl;
}

int main()
{
  std::vector<int> v;
  v.push_back(1);
  v.push_back(3);
  v.push_back(2);

  std::for_each(v.begin(), v.end(), print);
  std::for_each(v.begin(), v.end(), std::cout << boost::lambda::_1 << "\n");               
}

上述代码,print 只是实现了输出功能,如果可以在 std::for_each() 算法里面直接定义它的话,会更为方便,既能省去一个函数定义,又能使代码更为紧凑,使得算法与负责数据输出的函数不是局部性分离的

Boost.Lambda 定义了三个占位符,名为 _1, _2 和 _3。这些占位符是定义在单独的名字空间的。 例如代码第一个占位符是通过 boost::lambda::_1 来引用的。 使用时需包含头文件 boost/lambda/lambda.hpp

虽然 Boost.Lambda 非常强大,但也有一些缺点。 要在以上例子中插入换行的话,必须用 "\n" 来替代 std::endl 才能成功编译。 因为一元 std::endl 模板函数所要求的类型不同于 lambda 函数 std::cout << boost::lambda::_1 的函数,所以在此不能使用它。

加入if判断条件

#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/lambda/if.hpp>

int main()                                                                                                                               
{
  std::vector<int> v;
  v.push_back(1);
  v.push_back(3);
  v.push_back(2);

  //std::for_each(v.begin(), v.end(), boost::lambda::if_then(boost::lambda::_1 > 1, std::cout << boost::lambda::_1 << std::endl)); // 这里会报错
  std::for_each(v.begin(), v.end(), boost::lambda::if_then(boost::lambda::_1 > 1, std::cout << boost::lambda::_1 << "\n"));
}

只输出大于1的值

除了 boost::lambda::if_then(), Boost.Lambda 还提供了

 boost::lambda::if_then_else() 和 boost::lambda::if_then_else_return() 模板函数

lambda函数整体复杂度越高,可读性越低,实际使用应该权衡两者。

参考:

第 3 章 函数对象

boost bind使用指南

boost::function用法详解

猜你喜欢

转载自blog.csdn.net/guangyacyb/article/details/85333966