C++11新特性之模板的改进
C++11改进了编译器的解析规则,尽可能的将多个右尖括号(>)解析成模板参数结束符,方便我们编写模板的相关代码
一、模板的右尖括号
在C++98/03的泛型编程中,连续两个右尖括号(>>)会被编译器解释成右移操作符,而不是模板参数表的结束。
#include <QCoreApplication> #include <memory> #include <QDebug> template <typename T> struct Test { typedef T type; }; template <typename T> class A { public: void set_info(T info) {m_info = info;} T get_info() {return m_info;} private: T m_info; }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Test<A<int>>::type test; /* C++98/03标准中会出错,但是在C++11标准中是兼容的 */ test.set_info(1); qDebug()<< test.get_info(); return a.exec(); }
不过这种自动化的处理在某些时候会与老标准不兼容,比如下面的例子:
#include <QCoreApplication> #include <memory> #include <QDebug> template <int n> struct TestB { }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); TestB<100 >> 2> test; return a.exec(); }
在C++98/03的编译器中编译是没有问题的,但是C++11的编译器便会报错,可以改成
TestB<(100 >> 2)> test
二、模板的别名
在C++中可以通过typedef重定义一个类型
typedef INT int;
被重新定义的类型并不是一个新的类型,它仅仅是原有类型的一个别名,使用typedef重定义类型是很方便的,但是它也有限制,比如无法重定义一个模板,比如:
typedef std::map<std::string, int> map_int_t;
typedef std:map<std::string., std::string> map_str_t;
我们需要的实际上是一个固定以std::string为key的map,它可以映射到int或另一个std::string,然而这个需求仅仅通过typedef却很难办到。在C++98/03中往往不得不这样写:
#include <QCoreApplication> #include <memory> #include <QDebug> template <typename T> struct str_map { typedef std::map<std::string, T> type; }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); str_map<int>::type map_int; str_map<std::string>::type map_string; return a.exec(); }
现在C++11中可以重定义一个模板的语法:
#include <QCoreApplication> #include <memory> #include <QDebug> template <typename T> using str_map_t = std::map<std::string, T>; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); str_map_t<int> map_int; return a.exec(); }
这里使用新的using别名语法定义了std::map的模板别名str_map_t,比前面使用外敷模板加typedef构建的str_map,它完全就像是一个新的map类模板。C++11的using别名语法比typedef更加清晰,因为typedef的别名语法本质上类似一种解方程的思路,而using语法通过赋值来定义别名。下面是typedef和using定义函数指针模板的示例:
#include <QCoreApplication> #include <memory> #include <QDebug> /* C++98/03 */ template <typename T> struct func_t { typedef int (*type)(T, T); }; /* C++11 */ template <typename T> using func_t_1 = int (*)(T, T); int add(int a, int b) { return (a + b); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); func_t<int>::type func = add; qDebug() << "add:" << func(10, 20); func_t_1<int> func_1 = add; qDebug() << "C++11 add:" << func_1(20, 30); return a.exec(); }
三、函数模板的默认模板参数
#include <QCoreApplication> #include <memory> #include <QDebug> /* C++98/03中,类模板可以有默认的模板参数 */ template <typename T, typename U = int, U N = 0> struct Test { }; /* C++98/03中并不支持函数的默认模板参数 C++11新特性中,已经支持函数的默认模板参数 */ template <typename T = int, typename U> T func(U val) { return val; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << func<>(123); return a.exec(); }
从上面的示例可以看出,当所有模板参数都有默认参数时,函数模板的调用如同一个普通函数,对于类模板而言,哪怕所有参数都有默认参数,在使用时也必须在模板名后跟随"<>"来实例化。而函数模板则没有必须要求使用"<>"来实例化。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?