C++泛型程序设计---算法和提升

算法和提升

算法:所谓算法就是一个求解问题的过程或公式,即,通过一个有穷的计算序列生成结果。

函数模板就是普通函数的泛化:它能对多种数据类型执行动作,并且能用以参数方式传递来的各种操作实现要执行的工作,函数模板通常也称为算法。

提升:从一个(多个可能更好)具体的实例中泛化出一个算法,使之能适用于最大(但合理)范围的实参类型,即,限制一个算法(或一个类)只依赖必要的属性。

提升算法是一个由具体到抽象的过程,最重要的一点是保持性能并注意如何做才是合理的,如果试图覆盖所有可能的类型和操作,可能会把泛化推到一个不合理的程度。因此试图在缺乏具体实例的情况下直接从基本原理进行抽象,通常会使代码臃肿不堪,难以使用。

以下展示从一个具体实例提升出算法的过程:

//计算实参数组中double值的和
double add_double(double *array, int n)
{
    double sum{0};
    for(int i = 0; i < n; ++i)
    {
        sum = sum + array[i];
    }
    return sum;
}
//计算vector<int>中所有int值的和
int add_vector(const std::vector<int> &vec)
{
    int sum{0};
    for(auto iter = vec.cbegin(); iter != vec.cend(); ++iter)
    {
        sum += *iter;
    }
    return sum;
}

以上代码给出了两个具体的算法,现在以这两个具体的算法未起点,逐步设计出一个通用的算法。

先确定一个抽象的目标:

  • 不再明确说明元素是double还是int。
  • 不再明确说明是数组还是向量。

以下为第一个抽象版本:

template<typename Iter, typename Val = double>
Val sum_v1(Iter first, Iter last) noexcept
{
    Val sum = 0;
    while(first != last)
    {
        sum = sum + (*first);
        ++first;
    }
    return sum;
}

//测试
vector<int> vec = {200, 2, 3, 4};
int sum1 = sum_v1<vector<int>::iterator, int>(vec.begin(), vec.end()); //sum1 = 209

double ad[] = {100.0, 2, 3, 4};
double sum2 = sum_v1(ad, ad + 4); //sum2 = 109

以上抽象出了一个通用版本, 但是类型参数Val不能自动推到获得,显式的指定Val有点不友好。

下面针对Val类型参数、运算符做进一步抽象

template<typename Iter, typename Val, typename Operator>
Val sum_v2(Iter first, Iter last, Val sum, Operator opr) noexcept
{
    while(first != last)
    {
        sum = opr(sum, *first);
        ++first;
    }
    return sum;
}
//测试
vector<int> vec = {200, 2, 3, 4};
int sum = sum_v2(vec.begin(), vec.end(), 0, std::plus<int>());

double ad[] = {100.0, 2, 3, 4};
double product = sum_v2(ad, ad + 4, 1.0, std::multiplies<double>());

标准库对一些常见的运算,如plus、minus、multiplies,提供了对应的函数对象,可以作为实参。

设计算法最重要的指导原则是:在从具体实例提升算法的过程中,增加的特性(符号或运行时开销)不能损害算法的使用。

以下是标准库提供的plus函数对象

template<class _Ty = void>
struct plus
{   
    // functor for operator+
    typedef _Ty first_argument_type;
    typedef _Ty second_argument_type;
    typedef _Ty result_type;

    constexpr _Ty operator()(const _Ty& _Left, const _Ty& _Right) const
    {   
        // apply operator+ to operands
        return (_Left + _Right);
    }

};

template<>
struct plus<void>
{  
    // transparent functor for operator+
    typedef int is_transparent;

    template<class _Ty1, class _Ty2>
    constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const 
    -> decltype(static_cast<_Ty1&&>(_Left) + static_cast<_Ty2&&>(_Right))
    { 
        // transparently apply operator+ to operands
        return (static_cast<_Ty1&&>(_Left) + static_cast<_Ty2&&>(_Right));
    }
};
posted @ 2019-11-20 14:30  小肚哥  阅读(288)  评论(0编辑  收藏  举报