你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

深入学习C++函数模板

[复制链接]
gaosmile 发布时间:2020-8-24 22:39
在昨天的文章里面,我们给大家简单的分享了关于c++里面的函数模板的概念,通过代码示例,我们对函数模板的优势有了一个比较清楚的认识。咋们今天继续来深入学习函数模板。以下内容是今天知识学习总结笔记。
一、函数模板的深入理解:
1、函数模板深入理解:
  • 编译器从函数模板通过具体类型产生不同的函数
  • 编译器会对函数模板进行两次编译

-对模板代码本身进行编译,比如检查函数模板是否有语法上的错误
-对参数替换后的代码进行编译;也就是说,我们在调用函数模板的时候,编译器根据实际的参数类型,从而得到真正的函数,这个时候编译器会对这个函数进行第二次编译
2、注意事项:
  • 函数模板本身不允许隐式类型转换

-自动推导类型时,必须严格匹配
-显示类型指定时,能够进行隐式类型转换
代码实践:
代码版本一:
#include <iostream>
#include <string>

using namespace std;

class Test
{
     Test(const Test&);
public:
     Test()
     {

     }
};

template < typename T >
void Swap(T& a, T& b)
{
    T c = a;
    a = b;
    a = c;
}
typedef void(fun1)(int&, int&);
typedef void(fun2)(double&, double&);
typedef void(fun3)(Test&,Test&);

int main()
{
/* p1 和 p2 指向具体函数,但是 p1 和 p2 指向的具体函数是由函数模板具体产生,这里已经产生了函数,不是模板了,这两个函数是两个独立的不同的函数,我们通过函数打印地址,就能够明显发现 */
    fun1 *p1 = Swap;  // 定义函数指针,并能编译通过;这里编译器通过函数指针的类型自动推导 T 为 int; 编译器默默做的事有:1、首先进行自动推导;2、产生真正的 Swap() 函数;3、将实际生成的 Swap() 函数地址用于初始化 pi;
    fun2 *p2 = Swap;//编译器自动推导为double

    cout<<"p1 ="<<reinterpret_cast<void*>(p1)<<endl;//// 将 p1 这个指针的类型重解释为 void*
    cout<<"p2 ="<<reinterpret_cast<void*>(p2)<<endl;

   return 0;

}


输出结果:
root@txp-virtual-machine:/home/txp# ./a.out
p1 =0x400964
p2 =0x400990

代码版本二:
#include <iostream>
#include <string>

using namespace std;

class Test
{
     Test(const Test&);
public:
     Test()
     {

     }
};

template < typename T >
void Swap(T& a, T& b)
{
    T c = a;
    a = b;
    a = c;
}
typedef void(fun1)(int&, int&);
typedef void(fun2)(double&, double&);
typedef void(fun3)(Test&,Test&);

int main()
{
    fun1 *p1 = Swap;
    fun2 *p2 = Swap;

    fun3 *p3 = Swap;

    cout<<"p1 ="<<reinterpret_cast<void*>(p1)<<endl;
    cout<<"p2 ="<<reinterpret_cast<void*>(p2)<<endl;
    cout<<"p3 ="<<reinterpret_cast<void*>(p3)<<endl;
   return 0;

}

输出结果:
root@txp-virtual-machine:/home/txp# g++ test.cpp
test.cpp: In instantiation of ‘void Swap(T&, T&) [with T = Test]’:
test.cpp:32:16:   required from here
test.cpp:8:6: error: ‘Test::Test(const Test&)’ is private
      Test(const Test&);
      ^
test.cpp:19:11: error: within this context
     T c = a;
           ^

注解:显示编译器自动推导T为Test类,也就是Swap(T&,T&),然后就报了一个错误,说拷贝构造函数是私密的,所以也就导致Test c =a这里报错了
3、多参数函数模板
(1)函数模板可以定义任意多个不同的类型参数
template < typename T1, typename T2, typename T3 >
T1 Add(T2 a, T3 b)
{
   return static_cast<T1>(a+b);
}
(2)对于多参数函数模板
  • 无法自动推导返回值类型
  • 可以从左向右部分指定类型参数

//T1 = int, T2 = double, T3 = double
int r1 =Add<int>(0.5,0.8);
//T1 = int, T2 = float, T3 = double
int r2 =Add<int,float>(0.5,0.8);
//T1 = int, T2 = float, T3 = float
int r3 =Add<int,float,float>(0.5,0.8);
注:工程中将返回值参数作为第一个类型参数
代码实践:
#include <iostream>
#include <string>

using namespace std;

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


int main()
{
    // T1 = int, T2 = double, T3 = double
    int r1 = Add<int>(0.5, 0.8);

    // T1 = double, T2 = float, T3 = double
    double r2 = Add<double, float>(0.5, 0.8);

    // T1 = float, T2 = float, T3 = float
    float r3 = Add<float, float, float>(0.5, 0.8);

    cout << "r1 = " << r1 << endl;     // r1 = 1
    cout << "r2 = " << r2 << endl;     // r2 = 1.3
    cout << "r3 = " << r3 << endl;     // r3 = 1.3
   
    return 0;
}


输出结果:
root@txp-virtual-machine:/home/txp# ./a.out
r1 = 1
r2 = 1.3
r3 = 1.3

4、当函数重载遇到函数模板会发生什么?
(1)函数模板可以像普通函数一样被重载
  • C++编译器优先考虑普通函数
  • 如果函数模板可以产生一个更好的匹配,那么选择模板
  • 可以通过空模板实参列表限定编译器只匹配模板

微信图片_20200824223822.png
代码实践:
#include <iostream>
#include <string>

using namespace std;


template < typename T >
T Max(T a, T b)
{
    cout << "T Max(T a, T b)" << endl;
   
    return a > b ? a : b;
}

int Max(int a, int b)
{
    cout << "int Max(int a, int b)" << endl;
   
    return a > b ? a : b;
}

template < typename T >
T Max(T a, T b, T c)
{
    cout << "T Max(T a, T b, T c)" << endl;
   
    return Max(Max(a, b), c);
}

int main()
{
    int a = 1;
    int b = 2;
   
    cout << Max(a, b) << endl;                   // 普通函数 Max(int, int)
   
    cout << Max<>(a, b) << endl;                 // 函数模板 Max<int>(int, int)
   
    cout << Max(3.0, 4.0) << endl;               // 函数模板 Max<double>(double, double)
   
    cout << Max(5.0, 6.0, 7.0) << endl;          // 函数模板 Max<double>(double, double, double)
   
    cout << Max('a', 100) << endl;               // 普通函数 Max(int, int)
   
    return 0;
}


输出结果:
root@txp-virtual-machine:/home/txp# ./a.out
int Max(int a, int b)
2
T Max(T a, T b)
2
T Max(T a, T b)
4
I Max(T a, T b, T c)
T Max(T a, T b)
T Max(T a, T b)
7
int Max(int a, int b)
100

二、总结:
  • 函数模板通过具体类型产生不同的函数
  • 函数模板可以定义任意多个不同的类型参数
  • 函数模板中的返回值类型必须显示指定
  • 函数模板可以像普通函数一样被重载

好了,今天的分享就到这里,如果文章中有错误或者不理解的地方,可以交流互动,一起进步。

收藏 评论1 发布时间:2020-8-24 22:39

举报

1个回答
davidwyq 回答时间:2020-8-25 20:13:10
学习了

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版