1、简介
首先来看两个小的工具类result_of和ref,它们是本章其他库的基础。result_of使用了复杂的技巧来自动推导函数的返回值类型,ref可以包装对象的使用,在传递参数时消除对象拷贝的代价,或者将不可拷贝的对象变为可以拷贝。
bind是c++ 98标准库中函数适配器的增强,可以适配任意的可调用函数,包括函数指针、函数引用和函数对象,把它们变成一个新的函数对象,他是迈向c++函数式编程的第一步。function库则是对c/c++中的函数指针类型的增强,它能够容纳任意的可调用对象,可以配合bind使用。
最后讨论signals2库,它实现了威力强大的观察者模式,如果曾经用过c#的event/delegate或者Java的Observable/Observer,那么就会知道signals2对应c++的重要意义。
2、result_of
result_of是一个很小但很有用的组件,可以帮助程序员确定一个调用表达式的返回类型,主要用于泛型编程和其他Boost库组件,它已被收入TR1
原理
给定一个调用表达式,可以通过内部类型定义result_of<...>::type获得返回值的类型。
假设我们有一个类型Func,他可以是函数指针、函数引用或者成员函数指针,当然也可以是函数对象类型,它的一个实例是func。Func有一个operator(),参数是(T1 t1, T2 t2),这里T1、T2是两个模板类型,那么result_of<Func(T1, T2)>::type就是func(t1,t2)的返回值类型。
看看下面的代码(简单的一个例子):
#include "stdafx.h"
#include "boost/utility/result_of.hpp"
#include "iostream"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
typedef double (*Func)(double d);
Func fun = sqrt;
boost::result_of<Func(double)>::type x = fun(5.0);
cout << typeid(x).name() << endl;
return 0;
}
typedef double(*Func)(doubled);这行代码定义了一个函数指针类型Func,它的调用式接受一个double类型,返回类型为double。Func func = sqrt;这行代码声明了一个Func的一个实例变量func,一个具体的函数指针,并把它赋值为sqrt,运行一下,可以看到他显示出来的是double
这里并不具有什么吸引力,使用BOOST_AUTO也可以完成同样的功能:
#include "stdafx.h"
#include "boost/utility/result_of.hpp"
#include "boost/typeof/typeof.hpp"
#include "iostream"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
typedef double (*Func)(double d);
Func fun = sqrt;
BOOST_AUTO(x, fun(5.0));
cout << typeid(x).name() << endl;
return 0;
}
再看一下比较复杂的例子,让他返回参数的double类型吧:
#include "stdafx.h"
#include "boost/utility/result_of.hpp"
#include "boost/typeof/typeof.hpp"
#include "iostream"
using namespace std;
using namespace boost;
template<typename T, typename T1>
typename boost::result_of<T(T1)>::type call_func(T t, T1 t1)
{
return t(t1);
}
int _tmain(int argc, _TCHAR* argv[])
{
typedef double (*Func)(double d);
Func fun = sqrt;
BOOST_AUTO(x, call_func(fun, 5.0));
cout << typeid(x).name() << endl;
return 0;
}
当处于一个泛型上下文之中,周围没有真实的类型,而且没有表达式的时候,BOOST_AUTO就无能为力了,不过我们在实例中使用BOOST_AUTO结合result_of,这样就能正确获得模板类型的参数了。
注:
这里必须在result_of<>::type前加上关键字typename,否则编译器会认为type是result_of<>的成员变量,从而产生找不到声明的错误。