首页 > 编程语言 > 详细

C++ 基础(九)函数模板

时间:2021-07-31 11:22:57      阅读:19      评论:0      收藏:0      [点我收藏+]

1. 函数模板

  • 重载函数包含的代码相同,只是参数类型,返回值类型不同。更好的方法函数模板的方式。
  • 函数模板是参数化的函数定义。编译器需要时,就使用函数模板生成定义。
  • 模板的一个实例,或者模板的实例化。
template <typename T>
T larger(T a, T b)
{
    return a > b ? a : b;  
}
  • typename 关键字也可以是class,typename 也可以指代基本类型,相比class比较局限。

 

2. 创建函数模板的实例

  • 编译器根据实参自动推断替代T的类型。     // 模板实例推断

 

3. 模板类型参数

  • 按值传递可能造成不必要的赋值,替代方式是引用传递。
template <typename T>
const T& larger (const T& a, const T& b)
{
     return a > b ? a : b;
}

 

4. 显示指定模板实参

  • 显示地指定类型值,而不需要编译器进行推断: larger<double>(data,  19.6);  // 两个参数都使用double方式传递给函数

 

5. 函数模板的特例(指针参数)

  • 参数都是指针类型,产生的函数实例中会进行地址的操作,造成隐患。
  • 解决方法是定义模板的特例:
template <>
int * larger<int *> (int *a, int *b)
{
      return *a > *b ? a : b;
}
  • 模板特例需要放在原始模板的后面,特例也必须先声明再使用。

 

6. 函数模板和重载

  • 定义同名的函数,就可以重载函数模板,编译时优先使用函数。
  • 同另一个模板重载已有的模板。
  • 使用为指针类型定义的另一个模板重载原始模板。

 

7. 带有多个参数的函数模板

template <typename T1, typename T2>
??? larger(T1, T2)  // 实际定义时返回值需要再定义模板参数,但编译器仍然无法推断出返回值类型
{
    return a > b ? a : b;
}

template <typename TReturn, typename T1, typename T2>
TReturn larger(T1, T2)  // 实际定义时返回值需要再定义模板参数,但编译器仍然无法推断出返回值类型
{
    return a > b ? a : b;
}
  • 模板的参数列表放多个模板参数,这种情况下返回值类型无法确定,编译器也不能自动推断,需要调用时显示的指定。
  • 显示指定返回值类型:larger<size_t> (1.5, 2)

 

8. 函数模板的返回类型推断

  • 使用auto关键字
  • decltype 和 拖尾返回类型:
    • decltype(expression)能得到expression的计算结果的类型。
// decltype(拖尾类型)在函数模板中的应用

// step 1:编译失败,编译器从左往右处理模板,未能提前知道a和b的类型
template <typename T1, typename T2>
decltype(a>b?a:b) larger (T1 a, T2 b)
{
    return a > b ? a : b;
}

// step 2: 拖尾类型,auto告诉编译器需要推断返回值类型
template <typename T1, typename T2>
auto larger (T1 a, T2 b)  -> decltype (a > b ? a : b)
{
    return a > b ? a : b;
}

// step 3: 在模板内部使用decltype关键字
template <typename T1, typename T2>
auto vector_product(const std::vector<T1>& data1, const std::vector<T2>& data2)
{
    const auto count = std::min(data1.size(), data2.size());

    decltype(data1[0] * data2[0]) sum {};
    for(size_t i {}; i < count; ++i)
        sum += data1[i] * data2[i];

    return sum;
}
  • 对比decltype(auto),拖尾decltype()和auto:
    • C++14中引用decltype(auto):
    template <typename T1, typename T2>
    decltype(auto) larger(T1 a, T2 b)
    {
        return a > b ? a : b;
    }
    • 不同于auto,decltype(auto) 和 decltype()将推断为引用类型,并保留const修饰符,auto是值类型,也会进行不必要的复制。

 

9. 模板参数的默认值

  • 为模板参数指定默认值,在模板的实参列表指定模板实参的默认值。
  • 模板的一个参数名用在其他参数的默认值中。该名称在默认列表中位置应该靠前。

 

10. 非类型的模板参数

  • 非类型的模板参数类型可以是:整型(int,long等),对象类型的引用或指针,枚举类型,函数的引用或指针,类成员的指针。
  • 带有非类型的模板参数的函数模板定义:
template <typename T, int lower, int upper>
bool is_in_range(const T& value)
{
    return (value <= upper) && (value >= lower);
}

//调用方式
std::cout << is_in_range<double, 0, 500> (value);

// 优化写法
template <int lower, int upper, typename T>
bool is_in_range(const T& value)
{
    return (value <= upper) && (value >= lower);
}

// 调用如下,这样编译器可以推断实参类型
std::cout << is_in_range<0, 500> (value);
  • 使用固定大小数组实参的函数模板
template <typename T, size_t N>
T average(const T (&array) [N])
{
    T sum {};
    for (size_t i {}; i < N; i++)
        sum += array[i];
    return sum/N;
}
    • 当非参数类型N的实际数据不同时,会产生不同的函数实例,增加了代码量,但可以基于这种模板定义函数重载。

 

C++ 基础(九)函数模板

原文:https://www.cnblogs.com/yangdadahome/p/15077799.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!