ft.h :
#include <iostream>
// 本文件介绍 Function template c++20标准之前(不包括c++20)
// Syntax : template < parameter-list> function-declaration
template<typename T>
T add(T t1, T t2) {
std::cout << "primary template version" << std::endl;
return t1 + t2;
}
// 实例化 / instantiation
// 1. 显式实例化声明
// 模板形参被显式指定,无模板实参推导
extern template short add<short>(short, short);
// 对所有形参进行模板实参推导
extern template long add(long, long);
// 2. 隐式实例化 编译器从语境推导并自行实例化,不需要通过代码提供
// 特化 / specialization
// 特化版本的函数需要将声明放在头文件,定义放在源文件,这点与函数模板不同。
// 特化中可以显式指出替换类型
template<>
int add<int>(int t1, int t2);
// 也可以让编译器推导
template<>
double add(double t1, double t2);
// 函数模板和非模板函数的重载
// 一个非模板函数和具有相同类型的模板特化总是不同的。
// 不同函数模板的特化总是不同的,即使它们具有相同的类型。
// 注意,只有非模板函数和主模板(primary template)参与重载决议。
// 特化版本不参与重载。只有当重载决议选择了最匹配的主函数模板之后,其特化版本被考虑。
// 实际上函数模板的重载以及各自的特化版本选择问题是非常复杂的,涉及到各个特化版本的定义顺序
// (会改变特换版本究竟是谁的特化版本),函数调用是否使用ADL(改变参与重载决议的函数模板)等等。
// 见:https://en.cppreference.com/w/cpp/language/function_template 展开部分。
// 唯一的建议是:尽量少使用具有各种特化版本的函数模板重载机制,增加思维负担的同时使得代码逻辑依赖于各种不可控因素。
// 非模板函数被优先选择
//int* add(int* t1, int* t2);
// 函数模板的重载
template<typename T>
T* add(T* t1, T* t2) {
std::cout << "pointer primary template version" << std::endl;
*t1 = *t1 + *t2;
return t1;
}
main.cpp :
#include "ft.h"
#include <iostream>
// 显式实例化的定义
// 显式实例化和隐式实例化对于代码逻辑而言是相同的,
// 也无法改变不同实例化版本的定义(因为不是特化),只是控制不同版本在翻译单元的分布,减少重复生成。
// 如果只提供显式实例化的声明而没有显式实例化的定义,则会产生未定义的链接错误。
// 标准规定对于给定的参数列表,显式的实例化定义在程序中只能出现一次,不需要诊断。
// 显式实例化的函数模板或者类模板的成员函数不能够使用inline或者constexpr标记
// 构造函数没必要显式实例化
template short add<short>(short, short);
template long add(long, long);
template<>
int add<int>(int t1, int t2) {
std::cout << "int specialization" << std::endl;
return t1 + t2;
}
template<>
double add(double t1, double t2) {
std::cout << "double specialization" << std::endl;
return t1 + t2;
}
/*
int* add(int* t1, int* t2) {
std::cout << "non-template function" << std::endl;
*t1 = *t1 + *t2;
return t1;
}
*/
int main() {
add(2, 3);
add(2.0, 3.0);
add(char(2), char(3));
add(long(2), long(3));
int a = 3;
int b = 4;
add(&a, &b);
return 0;
}
output:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。