1.c++模板&类型

模板定义

模板类型

  1. 类型模板

    template <typename T1,typename T2>
    
  2. 非类型模板

    template <int MAXSIZE=4>
    

使用方式

模板可以使用在函数定义中或是类的定义中

函数模板

template <typename T1,typename T2>
inline double max(T1 const& a, T2 const& b)
max<int,double>(1,2.0) //使用

如果对于实际的模板类型要区分处理方式,可以使用模板特化,分为局部特化和全局特化

  1. 局部特化
    局部特化是指定部分模板类型的实际类型
    template <typename T>
    inline double max(T const& a, T const& b)
    max<int,int>(1,2) //使用
    
  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; //使用

如果对于实际的模板类型要区分处理方式,可以使用模板特化,分为局部特化和全局特化

  1. 局部特化
    局部特化是指定部分模板类型的实际类型
    template <typename T1>
    class Clazz<T1,T1>
    Clazz<long,long> clazz;//使用
    
  2. 全局特化
    全局特化是指定全部模板类型的实际类型
    template <>
    class Clazz<int>
    Clazz<int,int> clazz;//使用
    

类型

类型声明

  1. typedef X;
  2. using x=typename T表达式

类型使用

类型用来定义变量: T x;;

类型修改

类型修改后还是类型

  1. typename std::remove_reference<T>::type

    修改前修改后
    T&T&&T
  2. typename std::decay<T>::type

    修改前修改后
    T&T&&T
    const Tvolatile TT
    T[N]T*
    T() (函数类型)T(*)(...)
  3. typename std::remove_cv<T>::type

    修改前修改后
    const Tvolatile TT

类型测试

  1. typeid

    std::typeinfo &type=typeid(变量|typename T)) //使用方法

    type.name();

  2. std::is_lvalue_reference<typename T>::value

    判断类型是否是左值引用

  3. std::is_rvalue_reference<typename T>::value

    判断类型是否是右值引用

  4. std::is_const<typename T>::value

    判断类型是否为常量

  5. std::is_same<typename T1, typename T2>::value

    判断两个类型是否一致

变量类型预测

  1. auto
    auto 变量=表达式;//使用方法
    auto 会去除表达式的const属性
    auto & 不会去除表达式的const属性

  2. 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;
}
  1. 指定模板类型
    long a=1;checkType<long &>(a) //指定T1为long&,根据引用折叠,参数类型是long & &&必须使用左值赋值
    checkType<long>(1) //指定T1为long,根据引用折叠,参数类型是long  &&必须使用右值赋值
    checkType<long&&>(1) //指定T1为long&&,根据引用折叠,参数类型是long&& &&必须使用右值赋值
    
  2. 根据实际类型预测模板类型
    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; });
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值