template模板复习
0.引言
type ... pack-name(optional) (1)
typename|class ... pack-name(optional) (2)
type-constraint ... pack-name(optional) (3) (since C++20)
template < parameter-list > class ... pack-name(optional) (4) (until C++17)
template < parameter-list > typename|class ... pack-name(optional) (4) (since C++17)
1.包展开
#include<iostream>
// 此时 T 为包名
template <typename... T> //T... -> int,double,char
void fun(T... args){
}
int main(){
fun<int, double,char>(3,5.3,'c');
}
等价于:
#include<iostream>
template <typename... T> //T... -> int,double,char
void fun(T... args){
}
/* First instantiated from: insights.cpp:6 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void fun<int, double, char>(int __args0, double __args1, char __args2)
{
}
#endif
int main()
{
fun<int, double, char>(3, 5.2999999999999998, 'c');
}
2.(C++17) 折叠表达式
-
基于逗号的折叠表达式应用
-
折叠表达式用于表达式求值,无法处理输入(输出)是类型与模板的情形
#include<iostream> void fun(){} template <typename U, typename... T> void fun(U u, T... args){ std::cout<< u<<std::endl; fun(args...);//递归调用,进行展开打印 } int main(){ fun(1,2,"hello",'c'); }
等价于:
#include<iostream> void fun() { } template <typename U, typename... T> void fun(U u, T... args){ std::cout<< u<<std::endl; fun(args...);//递归调用,进行展开打印 } /* First instantiated from: insights.cpp:11 */ #ifdef INSIGHTS_USE_TEMPLATE template<> void fun<int, int, const char *, char>(int u, int __args1, const char * __args2, char __args3) { std::cout.operator<<(u).operator<<(std::endl); fun(__args1, __args2, __args3); } #endif /* First instantiated from: insights.cpp:8 */ #ifdef INSIGHTS_USE_TEMPLATE template<> void fun<int, const char *, char>(int u, const char * __args1, char __args2) { std::cout.operator<<(u).operator<<(std::endl); fun(__args1, __args2); } #endif /* First instantiated from: insights.cpp:8 */ #ifdef INSIGHTS_USE_TEMPLATE template<> void fun<const char *, char>(const char * u, char __args1) { std::operator<<(std::cout, u).operator<<(std::endl); fun(__args1); } #endif /* First instantiated from: insights.cpp:8 */ #ifdef INSIGHTS_USE_TEMPLATE template<> void fun<char>(char u) { std::operator<<(std::cout, u).operator<<(std::endl); fun(); } #endif int main() { fun(1, 2, "hello", 'c'); }
- 折叠表达式:
#include<iostream> template <typename... T> void fun(T... args){ ((std::cout<<args<<std::endl), ...); } int main(){ fun(1,2,"hello",'c');//递归调用,进行展开打印 }
等价于:
#include<iostream> template <typename... T> void fun(T... args){ ((std::cout<<args<<std::endl), ...); } /* First instantiated from: insights.cpp:8 */ #ifdef INSIGHTS_USE_TEMPLATE template<> void fun<int, int, const char *, char>(int __args0, int __args1, const char * __args2, char __args3) { (std::cout.operator<<(__args0).operator<<(std::endl)) , ((std::cout.operator<<(__args1).operator<<(std::endl)) , ((std::operator<<(std::cout, __args2).operator<<(std::endl)) , (std::operator<<(std::cout, __args3).operator<<(std::endl)))); } #endif int main() { fun(1, 2, "hello", 'c'); }
例2:
#include<iostream> template<typename ...Args> int sum(Args&&... args) { return (args + ... ); // OK } template<typename ...Args> int sum(Args&&... args) { return (... + args); // OK } int main(){ std::cout<< sum(1,2,3,4,5)<<std::endl;//15 }
等价于:
#include<iostream> template<typename ...Args> int sum(Args&&... args) { return (args + ... ); // OK } /* First instantiated from: insights.cpp:9 */ #ifdef INSIGHTS_USE_TEMPLATE template<> int sum<int, int, int, int, int>(int && __args0, int && __args1, int && __args2, int && __args3, int && __args4) { return __args0 + (__args1 + (__args2 + (__args3 + __args4))); } #endif int main() { std::cout.operator<<(sum(1, 2, 3, 4, 5)).operator<<(std::endl); }
3.完美转发
-
通常与万能引用结合使用
-
同时处理传入参数是左值或右值的情形
#include<iostream> void g(int&){ std::cout<<"l-reference\n"; } void g(int&&){ std::cout<<"r-reference\n"; } int main(){ int x = 3; g(x);//l-reference g(4);//r-reference }
#include<iostream> void g(int&){ std::cout<<"l-reference\n"; } void g(int&&){ std::cout<<"r-reference\n"; } template<typename T> void fun(T input){ void fun(T&& input){//万能引用,相同的结果 std::cout<<"Hello\n"; g(input); } int main(){ int x = 3; fun(x);//Hello\nl-reference fun(4);//Hello\nl-reference - T input 变为了左值,这并不是我们想要的结果,我们想要的是r-reference }
解决:完美转发
#include<iostream> #include<utility> void g(int&){ std::cout<<"l-reference\n"; } void g(int&&){ std::cout<<"r-reference\n"; } template<typename... T> void fun(T&&... args){ std::cout<<"Hello\n"; g(std::forward<T>(args)...); } int main(){ int x = 3; fun(x);//Hello\nl-reference fun(4);//Hello\nr-reference }
4.变量模板
-
template T pi = (T)3.1415926;
-
其它形式的变量模板
#include<iostream> #include<utility> template <typename T> T pi = (T)3.1415926; int main(){ std::cout<< pi<float> <<std::endl;//3.1415926 std::cout<< pi<int> <<std::endl;//3 }
#include<iostream> #include<utility> template <typename T> unsigned MySize = sizeof(T); int main(){ std::cout<< MySize<float> <<std::endl;//4 std::cout<< MySize<int> <<std::endl;//4 }
#include<iostream> #include<utility> template <typename T, unsigned v> unsigned MySize = (sizeof(T) == v); int main(){ std::cout<< MySize<float, 4> <<std::endl;//1 std::cout<< MySize<int, 2> <<std::endl;//0 }
is_same_v就是一个变量模板
template< class T, class U > inline constexpr bool is_same_v = is_same<T, U>::value;