C++函数模板

15 篇文章 0 订阅

参考 C++模板第二版

1.模板的检查

模板检查两次。

第一次是在模板定义阶段会去语法检查,但是并不包含参数的检查。

第二次是在模板实例化的过程中,为确保模板正确,模板会再次检查。

2.函数模板的写法

(1)typename 标识了一个类型参数

(2)typename也可以采用class,二者等价的,但是typename除了class,还可以接受其他类。

#include<iostream>
#include<string>
// using namespace std;

/*typename 标识了一个类型参数
typename也可以采用class,二者等价的,但是typename除了class,还可以接受其他类。
这里的T必须支持小于运算符,
因为a和b的比较时候得使用到它
此外T支持返回值,所以T必须是可拷贝的。
*/
    template<typename T>
    T max (T a,T b)
    {
        return b < a ? a: b;
        //返回a和b中的较大值
    }

    // {
    // template<class T>
    // T max (T a,T b)
    // {
    //     return b < a ? a: b;
    //     //返回a和b中的较大值
    // }
    // }
int main(){
    int i = 42;
    /*注意在调用 max()模板的时候使用了作用域限制符::。这样程序将会在全局作用域中查找
max()模板。否则的话,在某些情况下标准库中的 std::max()模板将会被调用,或者有时候不
太容易确定具体哪一个模板会被调用*/
    std::cout<< "max(7,i)"<<::max(7,i)<<std::endl;

    double f1 = 3.4;
    double f2 = -6.7;
    std::cout<<"max(f1,f2)"<<::max(f1,f2)<<std::endl;
    std::string s1 = "mathe";
    std::string s2 = "math";
    std::cout<<"max(s1,s2)"<<::max(s1,s2)<<std::endl;

    return 0;
}

// max(7,i)42
// max(f1,f2)3.4
// max(s1,s2)mathe

3.返回类型的模板参数推导

可以采用auto关键字

(1)auto max (T1 a,T2 b) ->typename std::decay<decltype(truea:b)>::type 是一种类型萃取的方法,可以获得返回类型的decay值,所谓的decay值就是去除引用以及const等特性,获得一个被削弱的返回值。

(2)auto本身返回的结果也是decay的。

#include<iostream>
#include<string>
#include<type_traits>
    template<typename T1,typename T2> 
    auto max (T1 a,T2 b) ->typename std::decay<decltype(true?a:b)>::type
    {
        return b < a ? a: b;
        //返回a和b中的较大值
    }
   //->typename std::decay<decltype(true?a:b)>::type
   //返回对应的类型,并且用decay去除引用等特性,返回其type为目标类型,再用typename获得结果
   //这样获得的结果将会是退化之后的结果
   //auto本身获得的结果就是退化的结果

// int i = 42;
// int const& ir = i; // ir 是 i 的引用
// auto a = ir; // a 的类型是 it decay 之后的类型,也就是 int

int main(){
   
    std::cout<< "max(7,2.5)"<<::max(7,2.5)<<std::endl;

    std::cout<< "max(7.1,2.5)"<<::max(7.1,2.5)<<std::endl;

    return 0;
}

(3)也可以采用std::common_type_t<T1,T2>,它也是退化的,会在返回结果中选择合适的值来返回。

#include<iostream>
#include<string>
#include<type_traits>
    template<typename T1,typename T2> 
    std::common_type_t<T1,T2> max (T1 a,T2 b) 
    {
        return b < a ? a: b;
        //返回a和b中的较大值
    }
   //std::common_type_t<T1,T2>      c++14
   //等价于 typename std::common_type<T1,T2>::type      c++11
   //它的结果也是退化的
 
int main(){
   
    std::cout<< "max(7,2.5)"<<::max(7,2.5)<<std::endl;

    std::cout<< "max(7.1,2.5)"<<::max(7.1,2.5)<<std::endl;

    return 0;
}

4.默认模板参数

直接将返回指的默认类型在template中去定义

#include<iostream>
#include<string>
#include<type_traits>
    template<typename T1,typename T2,typename T3 = std::decay_t<decltype(true?T1():T2())>>
    T3 max (T1 a,T2 b) 
    {
        return b < a ? a: b;
        //返回a和b中的较大值
    }
    
    //默认模板参数
    //std::decay_t<decltype(true?T1():T2())
    //typename T3 = std::common_type<T1,T2>>
  
 
int main(){
   
    std::cout<< "max(7,2.5)"<<::max(7,2.5)<<std::endl;

    std::cout<< "max(7.1,2.5)"<<::max(7.1,2.5)<<std::endl;

    return 0;
}

5.重载

(1)模块解析会优先选择非模板的函数

(2)如果可以实例化更匹配的函数,会选择模板函数

比如char可以转换为int,但是直接使用模板不用进行这种转换,所以会更加适合一些

(3)可以显示指示一个空的模板,它也会优先选择模板对象

(4)模板参数推导不能自动类型转换,但是如果用非模板函数可以进行自动类型转换,那么选择非模板的函数来使用的。

#include<iostream>
#include<string>
#include<type_traits>
    int max(int a,int b){
        std::cout<<"this is int"<<std::endl;
        return b<a?a:b;
    }
    template<typename T>
    T max(T a, T b){
        std::cout<<"this is template"<<std::endl;
        return b<a ? a:b;
    }
  
 
int main(){
   
   //模块解析会优先选择非模板的函数,
   //如果可以实例化更匹配的函数,会选择模板函数
   //比如char可以转换为int,但是直接使用模板不用进行这种转换,所以会更加适合一些。
    std::cout<< "max(7,42)"<<::max(7,42)<<std::endl;//this is int

    std::cout<< "max(7.0,42.0)"<<::max(7.0,42.0)<<std::endl;//this is template

    std::cout<< "max('a','b')"<<::max('a','b')<<std::endl;//this is template

    //可以显示指示一个空的模板,它也会优先选择模板对象。
    std::cout<< "max<>"<<::max<>(7,42)<<std::endl;//this is template

    std::cout<< "max<double>"<<::max<double>(7,42)<<std::endl;//this is template

    std::cout<< "max(11,'a')"<<::max(11,'a')<<std::endl;  //this is int
    //模板参数推导不能自动类型转换,但是这里可以用int max来作为函数使用,所以选择非模板参数来使用的。
    
    return 0;
}

(5)当重载函数模板的时候,你要保证对任意一个调用,都只会有一个模板匹配如果两个模板都是匹配的, 这会导致模板解析过程不知道该调用哪一个模板, 从而导致未知错误。因此当重载函数模板的时候,你要保证对任意一个调用,都只会有一个模板匹配

#include <iostream>
#include <string>
#include <type_traits>
template <typename T1, typename T2>
auto max(T1 a, T2 b)
{
    std::cout<<"this is first"<<std::endl;
    return b < a ? a : b;
}

template <typename RT, typename T1, typename T2>
RT max(T1 a, T2 b)
{
    std::cout<<"this is second"<<std::endl;
    return b < a ? a : b;
}

int main()
{

    auto a = ::max(4, 7.2); // uses first template
    auto b = ::max<long double>(7.2, 4); // uses second template
//当重载函数模板的时候,你要保证对任意一个调用,都只会有一个模板匹配
    //auto c = ::max<int>(4, 7.2);   //call of overloaded 'max<int>(int, double)' is ambiguous
// ERROR: both function templates match
// 两个模板都是匹配的, 这会导致模板解析过程不知道该调用哪一个模板, 从而导致未知错误。
// 因此当重载函数模板的时候,你要保证对任意一个调用,都只会有一个模板匹配
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值