• C++ template模板学习


    Template使用

    函数返回

    template <typename T>
    T function() {
        return T();
    }
    
    int main() {
        cout << function<int>() << endl;  // 显式指定模板参数类型
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    参数类型

    template<class A, class B>
    auto foo(A a, B b) {
    	return a + b; 
    }
    
    • 1
    • 2
    • 3
    • 4
    template<typename T> 
    int f(T) 
    { 
        return 1; 
    } 
    template<typename T> 
    int f(T*) 
    { 
        return 2; 
    } 
    int main() 
    { 
        std::cout << f(0) << std::endl;   // 自动检测模板参数类型
        std::cout << f((int*)0) << std::endl;   // 显式指定模板参数类型
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    C++ 14 auto 编译器推理返回类型

    template<typename T1, typename T2>
    auto max(T1 a, T2 b) {
        return b < a ? a : b;
    }
    
    auto a = ::max(2, 3.2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    decltype返回类型后置

    std::common_type_t公共类型作为返回类型

    Warning

    模板参数、调用参数不匹配

    #include 
     
    // 多个参数的函数木板                                                                                                                                                                                       
    template<typename RT, typename T1, typename T2>
    RT max(T1 a, T2 b) {
        using namespace std;
        cout << "调用的自定义模板函数...... " << endl;
        return b < a ? a : b;
    }
    
    double a = ::max(2, 3.2);  // ERROR
    double a = ::max<double, int, double>(2, 3.2);  // CORRECT, 需要显式指定
    double a = ::max<double>(2, 3.2);  // CORRECT
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 模板参数和调用参数不能完全匹配的时候需要显式指定类型
    • 必须显式指定直到最后一个不能确定的所有模板类型。

    无法解析外部符号

    Problem:
    将Template放在某个编译单元中出现“无法解析外部符号”的ERROR。

    Solution:

    • 方法1: 将类的声明和定义放在同一个template.h文件中。
    • 方法2: 在template.h文件末尾include "template.cpp"文件(实测:无法编译通过。参考链接:模板,无法解析的外部符号)。
    • 方法3: 在主函数所在的main.h中include .cpp文件(产生额外开销,所有引入main.h的文件均会加载)。

    Analysis:

    • 编译单元(translation unit):一个.cpp文件以及它所#include的所有.h文件(被扩展到包含它的.cpp文件里),然后编译器编译该.cpp文件为一个**.obj文件**。不同的cpp文件是分开编译的。再由连接器(linker)进行连接成为一个.exe文件
    • 主函数main编译时仅扩展template.h文件没有对此模板进行实例化的过程,所编译的obj文件没有对类模板进行实例化,不会生成二进制文件。
    • 在编译过程只有在同一个cpp文件及其include的文件中有引用函数模板的过程,函数模板才会转化成对应的函数。如:int test(1,3)编译的过程中会生成int test(int, int)这个函数,将参数实例化为int(特化引用)。如果没有函数模板调用的过程,就不会生成任何函数。

    模板调用顺序:
    背景:template.h中声明了模板函数但是具体实现放在了template.cpp文件中,主函数中引用到testFunc的一个特化实例。编译过程中,template和Main分别编译为template.obj和Main.obj。

    1. 模板函数testFunc在编译(compile)期间并未生成具体二进制代码(除非有特化的引用、函数模板调用,testFunc(double d)将参数实例化为double),在main函数中也没有嵌入这个函数的代码,可能只是包含了一句call testFunc之类的。
    2. 编译阶段,在main函数中发现了testFunc的引用,但是main.obj中没有相关的可执行代码(编译器认为该函数在别处定义 =》 需要链接LINK),在main中虽然引用到testFunc但是只提供了一个call虚拟地址而没有实际的执行代码。
    3. 链接阶段,将各个模块(编译期间生成的很多*.obj文件)组织起来。在LINK的时候把testFunc“嵌入”进来,就像是一个子过程。在main中从调用处jump到这里即可,执行完毕再从“中断点”继续执行后续语句。

    C++中使用函数模板出现“无法解析的外部符号”问题
    C++ 函数模板的返回类型如何确定?

    AUTO

    C++ 11 trailing return type

    auto func(T parameters) -> type;  
    // 等价于
    type func(T parameters);
    
    • 1
    • 2
    • 3

    auto 关键字只是一个占位符

    C++ 11 类型推导decltype

    template <typename U, typename V>
    auto add(U a, V b) -> decltype(a + b);
    
    • 1
    • 2

    通过 a + b (函数参数)的型别推断出 add 函数的返回类型。

    C++14 auto

    auto func(T param)
    {
        return xxx;
    }
    
    • 1
    • 2
    • 3
    • 4
    • auto & 只能返回左值引用。
    • auto && 既能返回左值引用,又能返回右值引用。
    • auto 只能返回一个型别。

    C++14 类型推导decltype(简化)

    decltype(auto) func(T parameter)
    {
        return xxx;
    }
    
    • 1
    • 2
    • 3
    • 4

    C++ 函数中的 auto

    模板元编程

    https://zhuanlan.zhihu.com/p/377145104

    按条件匹配:enable_if

    enable_if 利用了模板匹配的技巧和struct结构, 巧妙的将条件匹配分割成两种情况,
    一种是true的情况: 为结构绑定一个type
    一种是false的情况: 采取留空策略

    template <bool _Test, class _Ty = void>
    struct enable_if {}; // no member "type" when !_Test
    
    // 这个实现叫做部分具体化(partial specialization), 即: 第一个参数 () 采用具体值.
    // 当调用时传递的参数是true时, 一定会进入这个函数.
    // 当调用时传递的参数是true且不提供其他参数时,  会把自动合并上面一个enable_if的 ;
    // 当调用时传递的参数是true且提供其他参数时, _Ty 会替换成传递参数的类型(放弃void).
    template <class _Ty>
    struct enable_if<true, _Ty> { // type is _Ty for _Test
        using type = _Ty;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    enable_if_t

    基于模板的 SFINAE匿名类型参数 的基础概念上封装。

    enable_if_t 强制使用 enable_if 的 ::type 来触发 SFINAE 规则, 如果失败则跳过当前匹配进入下一个匹配.。

    C++模板 按条件匹配(enable_if_t)

    =》 面向数据编程

    概要设计(架构设计) -》集成测试
    详细设计 =》 单元测试

  • 相关阅读:
    node---express
    域名暂停解析是怎么回事?如何恢复解析?
    JSON&redis
    【面试题-007】说一下JVM原理
    【C++笔试强训】第十天
    SecureFX[po破] for Mac FTP/SSH传输工具[解] 安装教程
    P6776-[NOI2020]超现实树
    Git 分布式版本控制工具03Git常用命令:Git全局设置+本地与远程仓库操作获取Git仓库+标签操作+忽略名单+工作区、暂存区、版本库+分支操作+暂时保存
    WebGIS开发基础
    CSPM考试时间是什么时候?好考吗?
  • 原文地址:https://blog.csdn.net/qq_21980099/article/details/126604910