C++中的模板类&模板函数

 更新时间:2023年08月09日 10:42:45   作者:TiRan_Yang  
这篇文章主要介绍了C++中的模板类&模板函数用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

C++模板类&模板函数

模板类

模板类的定义使用 template<typename T> template<class T> ,将具有相同功能的代码合并,增加代码的简洁性和易读性。

例如在计算凸包的例子中,传入点的类型可以是自定义的 Point ,也可以是 pcl::point 之类。

例如在头文件中的定义如下:

template<typename T>
class POLYGON
{
public:
    POLYGON();
public:
    void convhull(std::vector<T> &input, std::vector<T> &result);
};

模板函数

如模板类中的 convhull 函数就是模板函数,模板函数的输入为各种类型的点,将计算后的凸包存在 result 中。 convhull 的模板参数只有T,也可以为该函数增加其它的模板参数。

例如,增加参数 T1

template<typename T>
class POLYGON
{
public:
    POLYGON();
	template<typename T1> void test(T1 a);
public:
    void convhull(std::vector<T> &input, std::vector<T> &result);
};

以上为模板类和模板函数是如何定义的,接下来将介绍它们是如何初始化的。模板函数有隐式实例化和显示实例化,但模板类只有显式实例化

1、隐式实例化

​ 在模板函数的初始化在类的内部,即函数的实现在类的内部,例如实现 pointFromVeh2grd ,在调用隐式实例化的模板函数时,系统会自动适配模板参数T。

template<typename T>
class POLYGON
{
public:
    POLYGON();
    T pointFromVeh2grd(const T &ptVeh, const double &vehX, const double &vehY, const float &vehYaw){
        return ptGrd;
    }
	template<typename T1> void test(T1 a);
public:
    void convhull(std::vector<T> &input, std::vector<T> &result);
};

2、显示初始化

模板函数的初始化在类的外部,模板类实例化 AXIS_CONVERT<int> ,这说明 AXIS_CONVERT 类只接受int类型的输入,如果输入类型,编译器会报错。

模板函数实例化 template void AXIS_CONVERT::test<double>(double); 同样 test 函数只接受 double 类型的输入。

//在源文件中进行显式初始化及实现
//显式初始化
template class AXIS_CONVERT<int>;
template void AXIS_CONVERT::test<double>(double);
//函数功能实现
template<typename T> template<typename T1>
void AXIS_CONVERT<T>::test(T a)
{
    std::cout<<a<<std::endl;
}

C++函数模板特化,类模板特化

模版与特化的概念

1. 函数模版与类模版

C++中模板分为函数模板和类模板

  • 函数模板:是一种抽象函数定义,它代表一类同构函数。
  • 类模板:是一种更高层次的抽象的类定义。

2. 特化的概念

所谓特化,就是将泛型的东西搞得具体化一些,从字面上来解释,就是为已有的模板参数进行一些使其特殊化的指定,使得以前不受任何约束的模板参数,或受到特定的修饰(例如const或者摇身一变成为了指针之类的东东,甚至是经过别的模板类包装之后的模板类型)或完全被指定了下来。

模板特化的分类

针对特化的对象不同,分为两类:函数模板的特化和类模板的特化

1. 函数模板的特化

当函数模板需要对某些类型进行特化处理,称为函数模板的特化。

2. 类模板的特化

当类模板内需要对某些类型进行特别处理时,使用类模板的特化。

3. 特化整体上分为全特化和偏特化

(1)全特化

就是模板中模板参数全被指定为确定的类型。

全特化也就是定义了一个全新的类型,全特化的类中的函数可以与模板类不一样。

(2)偏特化

就是模板中的模板参数没有被全部确定,需要编译器在编译时进行确定。

全特化的标志就是产生出完全确定的东西,而不是还需要在编译期间去搜寻适合的特化实现,貌似在我的这种理解下,全特化的 东西不论是类还是函数都有这样的特点

(3)两者的差别

模板函数只能全特化,没有偏特化(以后可能有)

模板类是可以全特化和偏特化的。

全特化的标志:template <>然后是完全和模板类型没有一点关系的类实现或者函数定义

偏特化的标志:template

函数模版特化:目前的标准中,模板函数只能全特化,没有偏特化

至于为什么函数不能偏特化,似乎不是因为语言实现不了,而是因为偏特化的功能可以通过函数的重载完成。

示例代码

1. 函数模板的特化

#include <iostream>
#include <cstring>
//	函数模板
template <class T>
int compare(const T left, const T right)
{
    std::cout <<"in template<class T>..." <<std::endl;
    return (left - right);
}
//  一个特化的函数模版
template < >
int compare<const char*>(const char* left, const char* right)
{
    std::cout <<"in special template< >..." <<std::endl;
    return strcmp(left, right);
}
//  这个其实本质是函数重载
int compare(char* left, char* right)
{
    std::cout <<"in overload function..." <<std::endl;
    return strcmp(left, right);
}
int main( )
{
    compare(1, 4);
    const char *left = "abcdef";
    const char *right = "wild_wolf";
    compare(left, right);
    return 0;
}

2. 类模板的特化

与函数模板类似,当类模板内需要对某些类型进行特别处理时,使用类模板的特化。

#include <iostream>
#include <cstring>
#include <cmath>
#include"tt.h"
// general version
template<class T>
class Compare
{
public:
    static bool IsEqual(const T& lh, const T& rh)
    {
        std::cout << "in the general class..." << std::endl;
        return lh == rh;
    }
};
// specialize for float
template<>
class Compare<float>
{
public:
    static bool IsEqual(const float& lh, const float& rh)
    {
        std::cout << "in the float special class..." << std::endl;
        return std::abs(lh - rh) < 10e-3;
    }
};
// specialize for double
template<>
class Compare<double>
{
public:
    static bool IsEqual(const double& lh, const double& rh)
    {
        std::cout << "in the double special class..." << std::endl;
        return std::abs(lh - rh) < 10e-6;
    }
};
int main(void)
{
    Compare<int> comp1;
    std::cout << comp1.IsEqual(3, 4) << std::endl;
    std::cout << comp1.IsEqual(3, 3) << std::endl;
    Compare<float> comp2;
    std::cout << comp2.IsEqual(3.14, 4.14) << std::endl;
    std::cout << comp2.IsEqual(3, 3) << std::endl;
    Compare<double> comp3;
    std::cout << comp3.IsEqual(3.14159, 4.14159) << std::endl;
    std::cout << comp3.IsEqual(3.14159, 3.14159) << std::endl;
    std::cout << hh<string>()("11") << std::endl;
    system("pause");
    return 0;
}

其中tt.h如下:

#include<string>
using std::string;
template<typename key>
class hh
{
public:
	size_t operator()(const key& k) const {
		size_t hashVal = 0;
		key tmp = k;
		while (tmp > 0) {
			hashVal = 37 * hashVal + tmp % 10;
			tmp /= 10;
		}
		return hashVal;
	}
};
template<>
class hh<string>
{
public:
	 size_t operator()(const string& key) {
		size_t hashVal = 0;
		std::cout << key << std::endl;
		for (char ch : key) {
			std::cout << "hasVal: " << hashVal << std::endl;
			hashVal = 37 * hashVal + ch;
		}
		return hashVal;
	}
};

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • C语言代码实现俄罗斯方块

    C语言代码实现俄罗斯方块

    这篇文章主要为大家详细介绍了C语言代码实现俄罗斯方块,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-01-01
  • c++归并排序详解

    c++归并排序详解

    归并排序遵循分治法的思想:将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后再合并这些子问题的解来建立原问题的解。分治模式在每层递归时都有三个步骤:分解、解决、合并。归并排序完全遵循该模式。
    2017-05-05
  • C语言实现经典windows游戏扫雷的示例代码

    C语言实现经典windows游戏扫雷的示例代码

    今天我们会用C语言实现一个经典的windows小游戏:扫雷。扫雷是一款单机小游戏,每次通关最高难度的关卡都会开心好一阵。现在学会了C语言,总算可以自己实现扫雷了。话不多说,咱们开始吧
    2022-10-10
  • C/C++实现string和int相互转换的常用方法总结

    C/C++实现string和int相互转换的常用方法总结

    在C++编程中,经常需要在字符串(string)和整型(int)之间进行转换,本文将详细介绍几种在C和C++中实现这两种类型转换的常用方法,有需要的可以参考下
    2024-01-01
  • 纯C语言实现五子棋

    纯C语言实现五子棋

    本文给大家分享的是去年制作的一个纯C语言实现的五子棋的代码,虽然没有带漂亮的界面,还是推荐给大家,有需要的小伙伴可以参考下。
    2015-03-03
  • C++中成员函数和友元函数的使用及区别详解

    C++中成员函数和友元函数的使用及区别详解

    大家好,本篇文章主要讲的是C++中成员函数和友元函数的使用及区别详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • c++实现二路归并排序的示例代码

    c++实现二路归并排序的示例代码

    这篇文章主要介绍了c++实现二路归并排序的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • C++ 哈希表的基本用法及说明

    C++ 哈希表的基本用法及说明

    这篇文章主要介绍了C++ 哈希表的基本用法及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • C语言深入讲解指针与结构体的使用

    C语言深入讲解指针与结构体的使用

    指针提供了对地址操作的一种方法,因此,使用指针可使得C语言能够更高效地实现对计算机底层硬件的操作。另外,通过指针可以更便捷地操作数组。C数组允许定义可存储相同类型数据项的变量,结构是C编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项
    2022-05-05
  • C++位图的实现原理与方法

    C++位图的实现原理与方法

    位图(bitset)是一种常用的数据结构,常用在给一个很大范围的数,判断其中的一个数是不是在其中。这篇文章主要给大家介绍了关于C++位图以及位图的实现原理与方法,需要的朋友可以参考下
    2021-05-05

最新评论