类模板
引入类模板的目的是为了解决C++
实现中减少代码冗余,这点与函数模板原因一致。
基本示例:类模板、静态函数、一般函数实例化。
C++17
中类模板的类型模板参数可以进行推断。(1) 隐式推断指南;(2) 自定义推断指南;
namespace _nsp2
{
template <typename T>
struct A
{
A(T val1, T val2)
{
std::cout << "val 1: " << val1 << ", 2: " << val2 << endl;
}
A(T val)
{
std::cout << "val : " << val << std::endl;
}
};
}
// _nsp2::A obj(5,6); // 这里推断出T为int
// _nsp2::A obj2(12.8); // 这里隐式推断出T为double
// _nsp2::A obj3(5, 6.9); // 类模板推断二义性,报错
针对类模板的构造函数都存在一个隐式的目标推断指南。
namespace _nsp3
{
template <typename T>
struct B
{
T m_b;
};
template <typename T>
B(T)->B<T>; // 自定义推断指南
}
// _nsp3::B<int> b; // 需要指定int
// _nsp3::B<int> b2{12}; // 初始化列表的方式来定义 m_b 15
// _nsp3::B b3(15); //上述存在自定义推断指南才可以之本句可执行
自定义推断指南,上述类对象
b
3
b_3
b3不会报错原因,1 类B
是聚合类C++聚合类,可以通过{}进行初始化;2 因为上述自定义推断指南的存在;
类模板使用规则
特化的类模板是通过泛化的类模板生成。因此,先有泛化类模板,才有特化版本的类模板。
类模板特化
类模板的特化分为全特化与偏特化两种方式。所谓全特化类模板就是所有类模板的变量都特化,而偏特化类模板就是特化部分变量或者变量的作用域范围有所改变。
类模板全特化
namespace nsp4
{
// 泛化版本
template <typename T, typename U>
struct TC
{
TC()
{
std::cout << "泛化版本..." << std::endl;
}
void fun()
{
std::cout << "fun()泛化版本..." << std::endl;
}
}
//---------------------
template <> //全特化:所有类型模板参数都存在具体代表
struct TC<int , int>
{
TC()
{
std::cout << "全特化版本..." << std::endl;
}
void fun()
{
std::cout << "fun()全特化版本..." << std::endl;
}
}
}
// _nsp4::TC<int, double> tc1;
// tc1.fun(); // 泛化版本
// _nsp4::TC<int, int> tc2;
// tc2.fun(); // 全特化版本 // 如果没有全特化版本,将会调用泛化版本
普通成员函数全特化
普通成员函数全特化版本,就是对全特化的某个类模板的成员函数重新定义下,见下面代码所示。
namespace nsp4
{
// 泛化版本
template <typename T, typename U>
struct TC
{
TC()
{
std::cout << "泛化版本..." << std::endl;
}
void fun()
{
std::cout << "fun()泛化版本..." << std::endl;
}
};
//--------------------
template <>
void TC<double, int>::fun()
{
std::cout << "普通成员函数fun()全特化版本..." << std::endl;
}
}
// _nsp4::TC<double, int> tc4;
// tc4.fun();
静态成员变量全特化
静态成员函数全特化原理与普通成员函数全特化类似,就是全特化某一个类版本后重新定义一下静态成员变量。
namespace nsp4
{
// 泛化版本
template <typename T, typename U>
struct TC
{
TC()
{
std::cout << "泛化版本..." << std::endl;
}
void fun()
{
std::cout << "fun()泛化版本..." << std::endl;
}
static int m_age; // 静态成员变量
};
//-----------------
template <typename T, typename U>
int TC<T, U>::m_age = 50;
template <>
int TC<double, int>::m_age = 100;
}
如果使用成员函数全特化与静态成员变量的全特化,就无法在对类进行全特化,因为重复全特化;
类模板偏特化
类模板的偏特化主要有以下两个方面:一个是类模板参数变量的偏特化;另外一个是类模板参数范围上的偏特化;
模板参数数量上的偏特化
类模板参数变量上的偏特化理解较为简单,就是存在某个固定变量类型,其它变量未确定的偏特化类模板。见下述代码:
namespace nsp4
{
// 泛化版本
template <typename T, typename U>
struct TC
{
TC()
{
std::cout << "泛化版本..." << std::endl;
}
void fun()
{
std::cout << "fun()泛化版本..." << std::endl;
}
static int m_age; // 静态成员变量
};
//-----------------
template <typename U>
struct TC<float, U>
{
std::cout << "TC<float, U>偏特化版本..." << std::endl;
}
void TC<float, U>::fun()
{
std::cout << "TC<float, U>::fun()偏特化版本..." << std::endl;
}
}
// _nsp4::TC<double, int> tc4;
// tc4.fun(); // 泛化
// _nsp4::TC<float, int> tc4;
// tc4.fun(); // 偏特化
模板参数范围上的偏特化
类模板参数范围上的偏特化,主要是指:变量作用域变小。例如: T → c o n s t T T\rightarrow{const T} T→constT、 T → T ∗ T\rightarrow{T^*} T→T∗等。
namespace nsp4
{
// 泛化版本
template <typename T, typename U>
struct TC
{
TC()
{
std::cout << "泛化版本..." << std::endl;
}
void fun()
{
std::cout << "fun()泛化版本..." << std::endl;
}
static int m_age; // 静态成员变量
};
//-----------------
template <typename T, typename U>
struct TC<const T, U*>
{
std::cout << "TC<const T, U*>偏特化范围版本..." << std::endl;
}
template <typename T, typename U>
void struct TC<const T, U*>::fun()
{
std::cout << "TC<const T, U*>::fun()偏特化版本..." << std::endl;
}
}
// _nsp4::TC<double, int> tc4;
// tc4.fun(); // 泛化版本
// _nsp4::TC<const double, int*> tc4;
// tc4.fun(); // 偏特化版本
小结
本篇主要记录一下类模板基本概念以及类模板特化的一些方式方法。留作后续查询记录,如果对你有所帮助深感喜悦。