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();
}
复制代码

从上面的示例可以看出,当所有模板参数都有默认参数时,函数模板的调用如同一个普通函数,对于类模板而言,哪怕所有参数都有默认参数,在使用时也必须在模板名后跟随"<>"来实例化。而函数模板则没有必须要求使用"<>"来实例化。

posted @   TechNomad  阅读(156)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示