一、class和typename区别
1. 大部分两者等价
2. 当需要显示指定类型时需要使用typename
template <class _Ty>
struct remove_cv<const _Ty> {
using type = _Ty;
/*template <template <class> class _Fn>
using _Apply = const _Fn<_Ty>;*/
template <template <class> class _Fn>
using _Apply = const typename _Fn<_Ty>::type;
//这里的typename不能改成class,因为编译器不知道type是啥,
//他无法感知到是不是正确的,因此需要你显示指定typename,他是个类型
};
不指定他是个类型编译器无法感知就会报错。
using remove_cv_t = typename remove_cv<_Ty>::type;
//源码里几乎都是如此显示指示他是个类型
二、模板模板参数
模板的参数传入的是一个模板,这就是所谓的模板模板参数。其实stl里很多模板都是这样实现的。std::vector<std::vector>,这种例子很多,都是容器套容器的,怎么实现,就是通过模板模板参数去实现的。让一个参数去接受模板参数。使用格式template <class> class _Fn
,需要指定接受什么样的模板参数,也就是能传入几个参数的模板template <class> class _Fn这个是1个参数``template <class t1, class t2> class _Fn
接受两个参数的模板。。。,下边用于介绍的就是可以接受一个参数的。
template <class _Ty>
struct remove_cv {
using type = _Ty;
template <template <class> class _Fn>
using _Apply = _Fn<_Ty>;
}
//使用方法如下。stl里很多模板都是这样实现的
remove_cv<remove_cv<const int>::type>::_Apply<remove_cv>::type b = 10;
//这有点绕
//remove_cv<const int>::type,调用类型匹配去除掉const属性
//remove_cv<int>::_Apply<remove_cv>,调用_Apply后,传入一个参数的模板。
//remove_cv::type 获取到模板参数里的类型
//int b = 10;
//就是以上四步。
测试使用demo如下(这个是去除const和volatile的模板方法)
#include<iostream>
template <class _Ty>
struct remove_cv { // remove top-level const and volatile qualifiers
using type = _Ty;
template <template <class> class _Fn>
using _Apply = _Fn<_Ty>; // apply cv-qualifiers from the class template argument to _Fn<_Ty>
};
template <class _Ty>
struct remove_cv<const _Ty> {
using type = _Ty;
template <template <class> class _Fn>
using _Apply = const _Fn<_Ty>;
/*template <template <class> class _Fn>
using _Apply = const typename _Fn<_Ty>::type;*/
};
template <class _Ty>
struct remove_cv<volatile _Ty> {
using type = _Ty;
template <template <class> class _Fn>
using _Apply = volatile _Fn<_Ty>;
};
template <class _Ty>
struct remove_cv<const volatile _Ty> {
using type = _Ty;
template <template <class> class _Fn>
using _Apply = const volatile _Fn<_Ty>;
};
template <class _Ty>
using remove_cv_t = typename remove_cv<_Ty>::type;
template<class T>
struct MyStructs
{
int a = 10;
};
int main(void)
{
remove_cv_t<remove_cv<const int>::type> a = 10;
remove_cv<remove_cv<const int>::type>::_Apply<remove_cv>::type b = 10;
remove_cv<const int>::_Apply<MyStructs> type;
//这个我在运行期间查看const属性被剥夺了
//type.a = 10;
//但是编译期间const属性在因此你没法去赋值。
return 0;
}
结果如下:
结论就是这种用法编译期间会保持设置的属性(因此如果错误使用就会发生编译错误),但是运行期不会。
总结
学习了可变参数,模板类型区别,模板模板参数对理解模板编程又进了一步
参考
https://blog.csdn.net/janeqi1987/article/details/87342975
https://blog.csdn.net/qq_45801299/article/details/112298619