第20课 - 函数模板

第20课 - 函数模板

    一.C++中如何交换两个变量的值

      

  void swap(int& a, int& b)
        {
            int t = a;
            a = b;
            b = t;
        }
        
        void swap(float& a, float& b)
        {
            float t = a;
            a = b;
            b = t;
        }
        
        void swap(char*& a, char*& b)
        {
            char* t = a;
            a = b;
            b = t;
        }

        这三个函数,除了类型不同,函数体代码完全相同。

      C++强调代码复用,如何解决这个代码冗余的问题?

    

    二.泛型编程

        2.1 不考虑具体数据类型的编程模式

            对于Swap函数可以考虑下面泛型的写法
                

                void Swap(T&a, T&b)
                {
                    T t = a;
                    a = b;
                    b = t;
                }

            Swap泛型写法中T不是一个具体的数据类型,而是泛指的任意数据类型。
        

        2.2 C++中的泛型编程->函数模板

            2.2.1 提供一种特殊的函数可用不同类型进行调用

            2.2.2 看起来和普通函数很相似,区别是类型可被参数化

             

               template <typename T>
                void Swap(T&a, T&b)
                {
                    T t = a;
                    a = b;
                     b = t;
                }

               

            2.2.3 函数模板的语法规则

                a.template关键字用于声明开始进行泛型编程

                b.typename关键字用于声明泛指类型

                

            2.2.4 函数模板的应用

                a.自动类型推导调用

                b.具体类型显示调用

 

                int a = 1;
                int b = 1;
                
                Swap(a,b);    -->自动类型推导:a和b均是int,因此参数T为int
                
                flaot fa = 3;
                flaot fb = 4;
            
                Swap<float>(fa, fb);-->显示类型调用:用float替换参数类型T

           

Source Example 2.2.4:
                #include <iostream>

                /* run this program using the console pauser or add your own getch, system("pause") or input loop */

                template <typename T>

                void Swap(T& a, T& b)
                {
                    T t = a;
                    a = b;
                    b = t;
                }

                int main(int argc, char** argv) {
                    
                    int a = 1;
                    int b = 0;
                    
                    Swap (a, b);
                    printf("a = %d, b = %d\n", a , b );
                    
                    float c = 1.2;
                    float d = 1.3;
                    
                    Swap<float>(c, d);
                    printf("c = %f, d = %f\n", c , d );
                    
                    char ca = 'a';
                    char cb = 'b';
                    
                    Swap (ca, cb);
                    printf("ca = %c, cb = %c\n", ca , cb );
                    
                    return 0;
                } 

            2.2.5 泛型算法:

              

 Source Example 2.2.5(选择排序):
                    #include <iostream>

                    /* run this program using the console pauser or add your own getch, system("pause") or input loop */

                    template <typename T>
                    void Swap(T& a, T& b)
                    {
                        T& t = a;
                        a = b;
                        b = t;
                    }

                    template <typename T>
                    void SelectSort(T array[], int length)
                    {
                        for (int i = 0; i < length; i++)
                        {
                            T min = array[i];
                            int index = i;
                            
                            for (int j = i + 1; j < length; j++)
                            {
                                if (array[j] < min)
                                {
                                    min = array[j];
                                    index = j;
                                }
                            }
                            
                            Swap(array[i], array[index]);
                        }
                    }

                    int main(int argc, char** argv) {
                        int array[] = {3,2,5,4,5};

                        SelectSort<int>(array, 5);
                        
                        for (int i = 0; i < 5; i++)
                        {
                            printf("array[%d] = %d\n", i ,array[i]);    
                        }
                            
                        return 0;
                    }

                    输出结果如下:

                    

            2.2.6 函数模板的深入理解

                a.编译器并不是把函数模板处理成能够处理任意类型的函数

                b.编译器从函数模板通过具体类型产生不同的函数

                c.编译器会对函数模板进行两次编译

                    在声明的地方对模板代码本省进行编译,会进行语法检查

                    在调用的地方对参数替换后的代码进行编译

                 d. 函数模版本身不允许隐士类型转换,自动推导类型时,必须严格匹配。显示类型指定时,可以进行隐式类型转换。

    

    三.函数重载遇上函数模板

        3.1 函数模板可以像普通函数一样被重载

            3.1.1 C++编译器优先考虑普通函数

            3.1.2 如果函数模板可以产生一个更好的匹配,那么选择模板

            3.1.3 可以通过空模板实参列表的语法限定编译器只通过模板匹配

     

   Source Example 3.1:
            #include <iostream>

            /* run this program using the console pauser or add your own getch, system("pause") or input loop */

            int Max(int a, int b)
            {
                printf("nomanl!\n");
                return a > b ? a : b;
            }

            template<typename T>
            T Max(T a, T b)
            {
                printf("template!\n");
                return a > b ? a : b;
            }

            template<typename T>
            T Max(T a, T b,T c)
            {
                        /* A,B是未知的泛型,会调用函数模板 */
                return Max(Max(a,b), c);
            }


            int main(int argc, char** argv) {
                int a = 1;
                int b = 2;
                
                /* 优先调用普通的Max函数 */
                printf("%d\n", Max(a,b));
                /* 通过空模板实参列表限定编译器调用模板函数 */
                printf("%d\n", Max<>(a,b));

                float fa = 3;
                float fb = 4;

                /* 由于是浮点型,会优先匹配函数模板 */
                printf("%f\n", Max(fa,fb));

                char ca = 5;
                char cb = 6;
                char cc = 7;
                
                printf("%d\n", (int)Max(ca, cb, cc));            
                
                /* 调用普通函数,因为模板不允许进行类型转换,普通函数可以 */
                Max('a', 100);
                return 0;
            }    

            输出结果如下:
                
            

        3.2 注意事项

            3.2.1 函数模板不允许自动类型转化

            3.2.2 普通函数能够进行自动类型转换

            

        3.3 函数模板可以定义任意多个不同的类型参数

            
            

            但是问题多个类型参数的模板可以支持自动类型推导吗?

                当声明的类型参数为返回值类型时,无法进行自动类型推导。

      

     Source Example 3.3
            #include <iostream>

            /* run this program using the console pauser or add your own getch, system("pause") or input loop */

            template<typename T1,typename T2,typename RT>
            RT Add(T1 a,T2 b)
            {
                return static_cast<RT>(a + b);
            }

            int main(int argc, char** argv) {
                
                /* 显示调用,没有问题 */
                printf("%lf", Add<char, float, double>('a', 100));
                
                /* 推导不出来返回值类型,会报错 */
                printf("%lf", Add('a', 100));
                
                return 0;
            }                      

            3.3.1 不完美的解决方案

                将返回类型参数声明放到第一个参数位置,调用时只需要显示声明返回类型参数即可

         

   Source Example 3.3.1
                #include <iostream>

                /* run this program using the console pauser or add your own getch, system("pause") or input loop */
                using namespace std;
                
                /* 返回类型要放在第一个 */
                template<typename RT,typename T1,typename T2>
                RT Add(T1 a,T2 b)
                {
                    return static_cast<RT>(a + b);
                }

                int main(int argc, char** argv) {
                    
                    /* 显示调用,没有问题 */
                    printf("%lf\n", Add<double, char, float>('a', 100));
                    
                                /* 提供返回类型 */
                    printf("%lf", Add<double>('a', 100.0f));
                    
                    return 0;
                }  

 


                

 

 

    四.小结

 

        4.1 函数模板其实是一个具有相同行为的函数家族

        4.2 函数模板可以根据类型实参对函数进行推导调用

        4.3 函数模板可以显示的指定类型参数

        4.4 函数模板可以被重载

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值