zoukankan      html  css  js  c++  java
  • 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));
        }
    };
    
  • 相关阅读:
    【php】PHP.ini配置文件中文
    IE6下背景图片不缓存问题或者document.execCommand("BackgroundImageCache",false,true)
    【javascript基础】之【IE著名bug——如果某个实例属性与标为[[DontEnum]]的某个属性同名,那么该实例属性不会出现在for in】
    【javascript基础】之【javascript1.6 Array 新增方法】之【indexOf】
    【javascript基础】之【javascript1.6 Array 新增方法】
    【javascript基础】之【确定元素坐标】
    【javascript基础】之【constructor属性】
    【javascript基础】之【__defineGetter__ 跟 __defineSetter__】
    jQuery Ajax 防止重复提交
    网页浏览器内核的比较研究
  • 原文地址:https://www.cnblogs.com/chengjundu/p/11897584.html
Copyright © 2011-2022 走看看