C++ template \ auto

Template使用

函数返回

template <typename T>
T function() {
    return T();
}

int main() {
    cout << function<int>() << endl;  // 显式指定模板参数类型
}

参数类型

template<class A, class B>
auto foo(A a, B b) {
	return a + b; 
}
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;   // 显式指定模板参数类型
}

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);

decltype返回类型后置

std::common_type_t<T1, T2>公共类型作为返回类型

Warning

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

#include <iostream>
 
// 多个参数的函数木板                                                                                                                                                                                       
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
  • 模板参数和调用参数不能完全匹配的时候需要显式指定类型
  • 必须显式指定直到最后一个不能确定的所有模板类型。

无法解析外部符号

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);

auto 关键字只是一个占位符

C++ 11 类型推导decltype

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

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

C++14 auto

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

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

decltype(auto) func(T parameter)
{
    return xxx;
}

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时, 一定会进入这个函数.
// 当调用时传递的参数是true且不提供其他参数时, <class _Ty> 会把自动合并上面一个enable_if的 <class _Ty = void>;
// 当调用时传递的参数是true且提供其他参数时, _Ty 会替换成传递参数的类型(放弃void).
template <class _Ty>
struct enable_if<true, _Ty> { // type is _Ty for _Test
    using type = _Ty;
};

enable_if_t

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

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

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

=》 面向数据编程

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值