using 定义模板别名
都知道 typedef可以用来定义类型别名。例如typedef unsigned int uint_t;
相当于给unsigned int类型起了个别名uint_t
如果有一个类型std::map<std::string, int>
想给它起别名。方便在程序中书写,那应该在没写呢?
typedef std::map<std::string, int> map_s_i; //现在,这么长的类型名,可以换成一个短类型,写起来方便多了 //使用 map_s_i mymap; mymap.insert({ "first",1 }); //插入元素到容器,容器中每个元素都是一个键值对
如果还有一种类型,std::map<std::string, std::string>,那么就要这样使用
typedef std::map<std::string, std::string> map_s_s; map_s_s mymap2; mymap2.insert({ "first","firstone" }); //key是"first",value是"firstone"
typedef痛点
如果在实际开发中有这样一个需求:希望定义一个类型,但这个类型不固定,例如对于 map类型容器中的元素,key是固定的 std::string类型,但是value不希望固定为 int或者固定位string,希望王可以由自己制定。
这个需求 typedef就很难办到,因为:typedef一般都是用来给固定类型起别名,而这里的类型名不固定,像一个模板一样,typedef无能为力。
C++98解决方案
通过一个类模板来实现
template <typename wt> struct map_s { typedef std::map<std::string, wt> type; //定义了一个类型 }; //main map_s<int>::type map1; //等价于 std::map<std::string, int> map1; map1.insert({ "first",1 });
可以看到为了实现比较通用的,要专门写一个类模板来达到目的,实现方式不太令人满意,所以C++11新标准解决了这个问题。
C++11解决方案
template<typename T> using str_map_t = std::map<std::string, T>; //main str_map_t<int> map1; map1.insert({ "first",1 });
分析代码:
既然是 template 开头,那么肯定是用于定义模板的,然后通过 using关键字给这个模板起来一个名字(别名模板),这里叫 str_map_t。后面这个std::map<std::string,T>是类型,所以不难看出using是用来给一个跟类型有关的模板起名字用的,有了名字,后续才能使用。
using与typedef用法对比
typedef unsigned int uint_t; using uint_t = unsigned int; //typedef 后的两个内容的位置反过 typedef int(*FunType)(int, int); using FunType = int(*)(int, int); //注意第一个圆括号中间的内容变成(*)了 //using 定义类型相关的模板(给函数指针起别名) template <typename T> using myfunc_M = int(*)(T, T); //综上可以看出using更符合编程习惯
总结
- 用 using 定义类型相关模板与定义普通类型相差不太多,只是在前面要加一个 template 开头的额模板参数列表。
- 在using 中使用的这种模板。既不是类模板也不是函数模板,可以看做是一种新的模板形式——别名模板