函数对象与整形操作元函数

函数对象

C++的STL大量算法实现中有许多需要进行运算的参数,如sort算法进行比较的方式、power进行运算的操作等。这些参数虽然可以使用一个函数指针的方式,将用户定义的特定操作以指针方式传入,但是函数指针不能满足抽象性的要求,而且无法与其他组件进行复杂的配接,因此诞生了函数对象。

函数对象

行为类似函数的一种对象,就实现来看,就是一个重载了函数运行操作符(operator())的类。
STL的函数对象执行某种特定的操作,基本覆盖了C++提供的所有操作符,包括算术类、关系类、逻辑类三种(C++11提供了三个按位运算函数对象bit_andbit_orbit_xor)。从操作数的个数上看可分为一元与二元两类,C++11之前只提供了一元和二元运算,但C++11支持了可变模版参数,因而可以让用户自定义任意参数的函数对象,同时也覆盖了STL提供的运算符的函数对象。以下仅以C++11之前的函数对象来讨论。

接口规则

STL定义了函数对象的两个基类unary_functionbinary_function,分别定义了一元与二元函数对象的接口规则。

template<typename Arg, typename Result>
struct unary_function{
    typedef Arg argument_type;
    typedef Result result_type;
};
template<typename Arg1, typename Arg2, typename Result>
struct binary_function{
    typedef Arg1 first_argument_type;
    typedef Arg2 second_argument_type;
    typedef Result result_type;
};

所有函数对象定义继承自上述两个基类即可符合STL的接口规则。这对于后续进行函数对象适配是非常重要的。

函数对象示例

//一元运算函数对象
template<typename T>
struct negate : public unary_function<T, T>
{
    T operator()(const T & x){ return -x;}
    //继承自unary_function并传入两个模版参数
    //返回值类型与参数类型相同
    //函数功能就是取传入参数的相反数
};

//二元运算函数对象
tempalte<typename T>
struct logical_and : public binary_function<T, T, bool>
{
    bool operator()(const T& x, const T& y)
    {
        return x && y;
    }
    //继承自binary_function,两个参数类型相同
    //返回值类型为bool
};

除了上述针对运算符提供的函数对象外,用户也可以自定义特殊功能的函数对象,如果是C++11则可以使用可变模版参数。

//此函数为证同所用,元素经过运算之后不会有任何变化
template<typename T>
struct identity : public unary_function<T, T>
{
    const T& operator()(const T& x) { return x; }

};

//针对map的pair对象,可以使用此函数选择第一个元素
template<typename Pair>
struct select1st : public 
    unary_function<Pair, typename Pair::first_type>
{
    const typename Pair::first_type & operator()
    (const Pair& x){ return x.first; }
};

元函数

针对编译期间的计算而诞生的元函数,从形式上看与函数对象的样子相似,但由于是在编译期,所操作的都是类型, 而编译期仅能支持整形常量值的运算,因此对于整形操作提供了类似STL函数对象的元函数。

整形外覆器

对于编译期间的运算必须是类型,故有如下整数类型的包装类:

template<class T, T N>
struct integer{
    //N为编译期间确定的常量,也就是该整形外覆器的值
    static const T value = N;

    typedef integer<T, N> type;
    typedef T value_type;

    typedef integer<T, N+1>::type next;
    typedef integer<T, N-1>::type prior;

    //提供显式类型转换操作符,将当前类型转换为对应的整数类型T
    operator T() const { return N; }
};

对于上述泛型的整数包装类,可以使用如下方式进行编译期的类型运算:

equal_to<ingeter<int, 10>, integer<int, 1> >::value
//equal_to为下面介绍的相等运算的元函数

操作示例

针对上述整形包装类,就得到了如下进行编译期运算的一系列元函数,分别有算术、位运算、关系、逻辑等操作,这些操作与对应于运行期的函数对象有着非常相似的形式。

//算术运算
template<typename T1, typename T2>
struct multiplies{
//common需要返回T1和T2运算后的范围更大的类型,需使用特化实现
    typedef common<T1::type,T2::type>::type value_type;
    static const value_type value = T1::value * T2::value;

    typedef multiplies<T1,T2> type;
    operator value_type(){ return value; }
};

//关系运算
//由于所有关系运算的结果都是bool类型,因此继承自bool_包装类实现
template<bool x>
struct bool_ {//bool包装类
    static const bool value = x;
    typedef bool value_type;
    typedef bool_<x> type;
    operator bool(){ return x; }
};
template<typename N1, typename N2>
struct equal_to : public bool_< N1::value == N2::value >
{};

//逻辑运算
template<typename N1, typename N2>
struct or_ : public bool_< N1::value && N2::value >
{};

与函数对象类似,整数操作元函数也可以进行证同操作、类型判断等:

template<class T>
struct identity{//证同,返回自身
    typedef typename T::value_type value_type;
    typedef typename T::type type;
    static const value_type value = T::value;
};

//偏特化版本实现引用类型判断
template<class T> struct is_reference : bool_<false>{};
template<class T> struct is_reference<T &> : bool_<true>{};

经过上述比较,可以发现在编译期和运行期都能将运算操作进行函数化(函数对象和元函数),这种方式对于构建高可扩展的程序非常有效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值