C++模板函数
函数模板
简单的函数模板
typename 可以使用class代替,但是不可以是使用struct代替。
template <typename T>
T mmax(T a, T b)
{
return b < a ? a : b;
}
模板类型推导
返回输入的类型,模板返回的类型由输入的决定
template <typename T>
T mmax(T a, T b)
{
return b < a ? a : b;
}
T是由输入的参数类型推导出来的,输入int T就是int型的。
如果a 和 b一个是int一个是double就需要定义两个typename。
template <typename T1, typename T2>
T1 mmax(T1 a, T2 b)
{
return b < a ? a : b;
}
返回类型的模板参数
当模板参数和调用参数之间没有关联的时候,且模板参数不确定的时候,必须在调用时显式指定模板实参。
添加三个模板类型,调用的时候必须指定模板的返回类型
template <typename TR, typename T1, typename T2>
TR mmax(T1 a, T2 b)
{
return b < a ? a : b;
}
std::cout << mmax<int>(10.3,6)<< endl;
返回值使用auto,编译器自动推导
从C++14开始,可以通过不声明任何返回类型来实现。
template <typename T1, typename T2>
auto mmax(T1 a, T2 b) -> typename std::decay<decltype(b < a ? a : b)>::type
{
return b < a ? a : b;
}
这里使用了类型特征 std::decay<>
,其返回结果类型为成员type
。 std::decay<>
在标准库<type_traits>
中定义。由于其成员type
是一个类型,因此必须用typename
修饰这个表达式才能访问它。
从C++11,C++标准库提供了一种指定选择“更一般的类型”的方法。std::common_type<>::type
萃取作为模板实参传递的两个或多个不同类型的“公共类型”。
C++11写法
template <typename T1, typename T2>
typename std::common_type<T1, T2>::type mmax(T1 a, T2 b)
{
return b < a ? a : b;
}
C++ 14 写法
template <typename T1, typename T2>
std::common_type_t<T1, T2> mmax(T1 a, T2 b)
{
return b < a ? a : b;
}
std::common_type<>
也是在标准库<type_traits>
中。
它可以萃取一个具有作为结果类型的type
成员的结构体。
其核心用法:
typename std::common_type<T1, T2>::type
从C++14 开始,可以通过在特征名称后面附加_t
并省略typename
和 ::type
std::common_type_t<T1, T2>
在内部它根据运算符?:
的语法规则或具体的类型的特化来选择类型。
默认模板实参
使用三目运算符?:
不过必须在a和b参数调用之前使用。
template <typename T1, typename T2, typename TR = std::decay_t<decltype(true ? T1() : T2())>>
TR mmax(T1 a, T2 b)
{
return b < a ? a : b;
}
使用std::common_type<>
类型特征来指定返回类型的默认值:
template <typename T1, typename T2, typename TR = std::common_type_t<T1, T2>>
TR mmax(T1 a, T2 b)
{
return b < a ? a : b;
}
需要注意的是,std::common_type<>
会进行退化,因此返回类型不可能变成引用类型。
模板参数
template<typename T, int N>
void Print(T a)
{
std::vector<T> num;
for(int i = 0; i < N; ++i)
{
num.push_back(i + a);
}
for(auto& value : num)
{
std::cout << static_cast<T>(value) << std::endl;
}
}
重载函数模板
int mmax(int a, int b)
{
return b < a? a : b;
}
template<typename T>
T mmax(T a, T b)
{
return b < a? a : b;
}
std::cout << mmax(10.3,6.1)<< endl; //使用的模板函数
一个模板函数可以和一个普通函数同名且可以用相同类型实例化的函数模板共存。在所有其他因素都相同的情况下,重载解析过程优先选择非模板函数。
std::cout << mmax('a', 6) << endl;
由于模板参数推导不允许自动类型转换,而普通函数可以,因此此函数使用的是非模板函数。
template <typename T1, typename T2>
auto mmax(T1 a, T1 b)
{
return b < a ? a : b;
}
template <typename TR, typename T1, typename T2>
TR mmax(T1 a, T1 b)
{
return b < a ? a : b;
}
auto a = mmax<double, int>(10.3, 6);
使用第一个模板
auto b = mmax<long, double>(10.3, 6);
使用第二个模板
auto c = mmax<int>(10.3, 6);
错误: 两个模板都能匹配
两个模板都能匹配通常会造成重载解析过程中无从选择,并产生歧义。因此在重载函数模板时,应该确保对于任何调用,其中只有一个与之匹配。
constexpr关键字
从C++11开始,可以使用关键字constexpr来启用在编译器使用代码计算某些数值的功能。
constexpr int Sum(int a, int b)
{
return a + b;
}
int Iarray[Sum(10,3)];
使用这个关键字修饰函数就可以自定义数组大小,如果不用这个关键字修饰代码编译会出错的。