模板定义
模板类型
-
类型模板
template <typename T1,typename T2>
-
非类型模板
template <int MAXSIZE=4>
使用方式
模板可以使用在函数定义中或是类的定义中
函数模板
template <typename T1,typename T2>
inline double max(T1 const& a, T2 const& b)
max<int,double>(1,2.0) //使用
如果对于实际的模板类型要区分处理方式,可以使用模板特化,分为局部特化和全局特化
- 局部特化
局部特化是指定部分模板类型的实际类型template <typename T> inline double max(T const& a, T const& b) max<int,int>(1,2) //使用
- 全局特化
全局特化是指定全部模板类型的实际类型template <> inline double max(double const& a, double const& b) max<double,double>(1.0,2.0) //使用
类模板
template <typename T1,typename T2>
class Clazz
Clazz<long,int> clazz; //使用
如果对于实际的模板类型要区分处理方式,可以使用模板特化,分为局部特化和全局特化
- 局部特化
局部特化是指定部分模板类型的实际类型template <typename T1> class Clazz<T1,T1> Clazz<long,long> clazz;//使用
- 全局特化
全局特化是指定全部模板类型的实际类型template <> class Clazz<int> Clazz<int,int> clazz;//使用
类型
类型声明
- typedef X;
- using x=typename T表达式
类型使用
类型用来定义变量: T x;
;
类型修改
类型修改后还是类型
-
typename std::remove_reference<T>::type
修改前 修改后 T&
或T&&
T
-
typename std::decay<T>::type
修改前 修改后 T&
或T&&
T
const T
或volatile T
T
T[N]
T*
T()
(函数类型)T(*)(...)
-
typename std::remove_cv<T>::type
修改前 修改后 const T
或volatile T
T
类型测试
-
typeid
std::typeinfo &type=typeid(变量|typename T)) //使用方法
type.name();
-
std::is_lvalue_reference<typename T>::value
判断类型是否是左值引用
-
std::is_rvalue_reference<typename T>::value
判断类型是否是右值引用
-
std::is_const<typename T>::value
判断类型是否为常量
-
std::is_same<typename T1, typename T2>::value
判断两个类型是否一致
变量类型预测
-
auto
auto 变量=表达式;//使用方法
auto 会去除表达式的const属性
auto & 不会去除表达式的const属性 -
decltype
decltype(变量); //使用方法,decltype(变量1) 返回的是一个 typename,也就是一个类型
参数类型预测
template <typename T1>
void checkType(T1 &&a)
{
std::string typeids = typeid(T1).name();
std::cout << "type=" << typeid(a).name()
<< " is lvalue reference=" << std::is_lvalue_reference<decltype(a)>::value
<< " is rvalue reference=" << std::is_rvalue_reference<decltype(a)>::value
<< " is const=" << std::is_const<decltype(a)>::value
<< std::endl;
auto a1 = a;
decltype(a) a2 = a;
// T1 a2=a;
typename std::remove_reference<T1>::type a3 = a;
typename std::decay<T1>::type a4 = a;
typename std::remove_cv<T1>::type a5 = a;
std::cout << "auto type=" << typeid(a1).name()
<< " is lvalue reference=" << std::is_lvalue_reference<decltype(a1)>::value
<< " is rvalue reference=" << std::is_rvalue_reference<decltype(a1)>::value
<< " is const=" << std::is_const<decltype(a1)>::value
<< std::endl;
std::cout << "decltype type=" << typeid(a2).name()
<< " is lvalue reference=" << std::is_lvalue_reference<decltype(a2)>::value
<< " is rvalue reference=" << std::is_rvalue_reference<decltype(a2)>::value
<< " is const=" << std::is_const<decltype(a2)>::value
<< std::endl;
std::cout << "remove_reference type=" << typeid(a3).name()
<< " is lvalue reference=" << std::is_lvalue_reference<decltype(a3)>::value
<< " is rvalue reference=" << std::is_rvalue_reference<decltype(a3)>::value
<< " is const=" << std::is_const<decltype(a3)>::value
<< std::endl;
std::cout << "decay type=" << typeid(a4).name()
<< " is lvalue reference=" << std::is_lvalue_reference<decltype(a4)>::value
<< " is rvalue reference=" << std::is_rvalue_reference<decltype(a4)>::value
<< " is const=" << std::is_const<decltype(a4)>::value
<< std::endl;
std::cout << "remove_cv type=" << typeid(a5).name()
<< " is lvalue reference=" << std::is_lvalue_reference<decltype(a5)>::value
<< " is rvalue reference=" << std::is_rvalue_reference<decltype(a5)>::value
<< " is const=" << std::is_const<decltype(a5)>::value
<< std::endl;
}
- 指定模板类型
long a=1;checkType<long &>(a) //指定T1为long&,根据引用折叠,参数类型是long & &&必须使用左值赋值 checkType<long>(1) //指定T1为long,根据引用折叠,参数类型是long &&必须使用右值赋值 checkType<long&&>(1) //指定T1为long&&,根据引用折叠,参数类型是long&& &&必须使用右值赋值
- 根据实际类型预测模板类型
long a=1;checkType(a);//不指定T1,传入是左值类型,说明T1 &&为左值引用,根据引用折叠规则,预测T1为long& checkType(1);//不指定T1,传入是右值类型,说明T1 &&为右值引用,根据引用折叠规则,预测T1为long&&
引用折叠规则在《左值和右值》中介绍
可变参数类型预测
template <typename RetType, typename... ArgsType>
int emitEvent( ArgsType &&...args)
{
//1.使用std::forward_as_tuple将参数列表转化成tuple对象,然后使用apply遍历tuple每个参数并用decltype预测变量类型
std::tuple<std::decay_t<ArgsType>...> t = std::forward_as_tuple(std::forward<ArgsType>(args)...);
std::apply([](auto&&... args){
((std::cout << typeid(decltype(args)).name() << ", "), ...);
},t);
//2.使用std::tuple将类型列表转化成类型元素的tuple对象,使用tuple_element获取tuple对象指定位置的类型元素
std::cout <<typeid(typename std::tuple_element<0, std::tuple<ArgsType...> >::type).name()<< ", ";
std::cout <<typeid(typename std::tuple_element<1, std::tuple<ArgsType...> >::type).name();
return 1;
}
函数类型预测
构造函数类型
因为有时候函数会传入返回类型和参数类型,所以需要使用返回类型和参数类型构造函数类型
typedef Ret function_type(Args...); //获取普通函数类型
using stl_function_type = std::function<function_type>;//获取std::function类型
typedef Ret(*pointer)(Args...);//获取函数指针类型
获取函数参数和函数返回值类型
#ifndef SRC_UTIL_FUNCTION_TRAITS_H_
#define SRC_UTIL_FUNCTION_TRAITS_H_
#include <tuple>
#include <functional>
namespace toolkit {
template<typename T> //原始模板T
struct function_traits;
//普通函数 [AUTO-TRANSLATED:569a9de3]
//将类型T特化成普通函数类型Ret(Args)
template<typename Ret, typename... Args>
struct function_traits<Ret(Args...)>
{
public:
enum { arity = sizeof...(Args) }; //获取参数个数
typedef Ret function_type(Args...); //获取普通函数类型
typedef Ret return_type; //获取返回类型
using stl_function_type = std::function<function_type>;//获取std::function类型
typedef Ret(*pointer)(Args...);//获取函数指针类型
template<size_t I>
struct args
{
static_assert(I < arity, "index is out of range, index must less than sizeof Args");
using type = typename std::tuple_element<I, std::tuple<Args...> >::type; //获取第I个参数的类型
};
};
//函数指针 [AUTO-TRANSLATED:bc15033e]
//将类型T特化成函数指针类型Ret(*)(Args),同时继承普通函数类型,最后收束到普通函数类型处理
template<typename Ret, typename... Args>
struct function_traits<Ret(*)(Args...)> : function_traits<Ret(Args...)>{};
//std::function
//将类型T特化成std::function类型,同时继承普通函数类型,最后收束到普通函数类型处理
template <typename Ret, typename... Args>
struct function_traits<std::function<Ret(Args...)>> : function_traits<Ret(Args...)>{};
//member function
//将类型T特化成类的成员函数类型,同时继承普通函数类型,最后收束到普通函数类型处理
#define FUNCTION_TRAITS(...) \
template <typename ReturnType, typename ClassType, typename... Args>\
struct function_traits<ReturnType(ClassType::*)(Args...) __VA_ARGS__> : function_traits<ReturnType(Args...)>{}; \
FUNCTION_TRAITS()
FUNCTION_TRAITS(const)
FUNCTION_TRAITS(volatile)
FUNCTION_TRAITS(const volatile)
//函数对象 [AUTO-TRANSLATED:a0091563]
//将类型T特化成函数对象类型,同时继承普通函数类型,最后收束到普通函数类型处理
template<typename Callable>
struct function_traits : function_traits<decltype(&Callable::operator())>{};
} /* namespace toolkit */
#endif /* SRC_UTIL_FUNCTION_TRAITS_H_ */
工具使用方法:
template <typename FUNC>
//func可以传入
/**
1.普通函数类型
2.函数指针类型
3.std::function类型
4.类的成员函数
5.函数对象
*/
void addListener(FUNC &&func)
{
//参数个数
std::cout << "argc " << toolkit::function_traits<typename std::remove_reference<FUNC>::type>::arity << std::endl;
//参数类型
std::cout << "arg0 " << " " << typeid(typename toolkit::function_traits<typename std::remove_reference<FUNC>::type>::args<0>::type).name()<< std::endl;
std::cout << "arg1 " << " " << typeid(typename toolkit::function_traits<typename std::remove_reference<FUNC>::type>::args<1>::type).name()<< std::endl;
//返回类型
std::cout << "ret " << typeid(typename toolkit::function_traits<typename std::remove_reference<FUNC>::type>::return_type).name()<< std::endl;
//函数类型
std::cout << "std::function " << typeid(typename toolkit::function_traits<typename std::remove_reference<FUNC>::type>::stl_function_type).name()<< std::endl;
std::cout << "function " << typeid(typename toolkit::function_traits<typename std::remove_reference<FUNC>::type>::function_type).name()<< std::endl;
std::cout << "function pointer " << typeid(typename toolkit::function_traits<typename std::remove_reference<FUNC>::type>::pointer).name()<< std::endl;
}
addListener([](int x, long y) -> int{ return 1; });