c++11新特性篇-模板的优化

模板的右尖括号

这一点很简单,之前是在使用模板的时候,两个连续的<<会被认为是左移运算符,报错会让你用空格隔开,现在已经没什么问题,这里也不再多说,把之前版本会出问题的代码放在下面,(不再需要注意这个了)。

vector<vector<int>> v;

可变参数模板

可变参数模板(Variadic Templates)是C++11引入的一个重要特性,它允许你编写能够接受任意数量参数的模板函数和类。这个特性对于许多泛型编程和元编程的场景非常有用。可变参数模板使用了递归展开(Recursive Expansion)的技术,允许模板函数或类模板在编译时处理任意数量的参数。

        基本语法

可变参数模板的基本语法如下:

template<typename... Args>
void myFunction(Args... args) {
    // 函数体
}

在这个例子中, Args...是一个模板参数包(template parameter pack),它表示可以接受任意数量的模板参数。在函数体内,你可以像使用普通参数一样使用这个参数包。

        递归展开

为了处理参数包中的每一个参数,你通常需要使用递归展开的技术。C++11引入了递归展开的语法,使得你可以在编译时展开参数包,逐个处理其中的参数。

下面是一个简单的例子,演示了如何递归展开一个参数包,并计算参数的总和:

template<typename T>
T sum(T value) {
    return value;
}

template<typename T, typename... Args>
T sum(T first, Args... args) {
    return first + sum(args...);  // 递归展开参数包
}

int main() {
    int total = sum(1, 2, 3, 4, 5);
    std::cout << "Total: " << total << std::endl;  // 输出:Total: 15
    return 0;
}

在这个例子中,sum函数使用了递归展开技术,首先处理第一个参数 first,然后递归处理剩余的参数 args...,直到参数包为空。通过递归展开,这个函数能够接受任意数量的参数并计算它们的总和。

        实际应用

可变参数模板的应用非常广泛,例如,用于实现格式化字符串、元编程、类型转换等。在STL中,很多泛型算法和容器也使用了可变参数模板来提供更大的灵活性。

总的来说,可变参数模板是C++11引入的一个强大特性,它提供了更灵活的泛型编程方式,使得编程变得更加方便和高效。

模板别名

C++11引入了模板别名,允许你为模板类型定义一个简洁的别名,使得代码更易读。

这个比较简单,使用using关键字即可

template<typename T>
using Vec = std::vector<T>;

Vec<int> numbers; // 等同于 std::vector<int> numbers;

模板模板参数

C++11允许你使用模板作为模板的参数,这样可以更灵活地设计泛型类和函数。

template<template<typename> class Container>
class Wrapper {
    // ...
};

Wrapper<std::vector> vecWrapper;  // 使用std::vector作为Container模板参数

默认模板参数

这部分内容主要参考模板的优化 | 爱编程的大丙

在C++98/03标准中,类模板可以有默认的模板参数:

#include <iostream>
using namespace std;

template <typename T=int, T t=520>
class Test
{
public:
    void print()
    {
        cout << "current value: " << t << endl;
    }
};

int main()
{
    Test<> t;
    t.print();

    Test<int, 1024> t1;
    t1.print();

    return 0;
}

但是不支持函数的默认模板参数,在C++11中添加了对函数模板默认参数的支持:

#include <iostream>
using namespace std;

template <typename T=int>	// C++98/03不支持这种写法, C++11中支持这种写法
void func(T t)
{
    cout << "current value: " << t << endl;
}

int main()
{
    func(100);
    return 0;
}

函数模板有默认参数的时候,调用起来和普通函数无异。类模板即使有默认参数,也需要<>进行实例化操作。

另外:函数模板的默认模板参数在使用规则上和其他的默认参数也有一些不同,它没有必须写在参数表最后的限制。这样当默认模板参数和模板参数自动推导结合起来时,书写就显得非常灵活了。我们可以指定函数模板中的一部分模板参数使用默认参数,另一部分使用自动推导,比如下面的例子:

#include <iostream>
#include <string>
using namespace std;

template <typename R = int, typename N>
R func(N arg)
{
    return arg;
}

int main()
{
    auto ret1 = func(520);
    cout << "return value-1: " << ret1 << endl;

    auto ret2 = func<double>(52.134);
    cout << "return value-2: " << ret2 << endl;

    auto ret3 = func<int>(52.134);
    cout << "return value-3: " << ret3 << endl;

    auto ret4 = func<char, int>(100);
    cout << "return value-4: " << ret4 << endl;

    return 0;
}

测试代码输出的结果为:

return value-1: 520
return value-2: 52.134
return value-3: 52
return value-4: d

根据得到的日志输出,分析一下示例代码中调用的模板函数:

auto ret = func(520);
        函数返回值类型使用了默认的模板参数,函数的参数类型是自动推导出来的为int类型。
auto ret1 = func<double>(52.134);
        函数的返回值指定为double类型,函数参数是通过实参推导出来的,为double类型
auto ret3 = func<int>(52.134);
        函数的返回值指定为int类型,函数参数是通过实参推导出来的,为double类型
auto ret4 = func<char, int>(100);
        函数的参数为指定为int类型,函数返回值指定为char类型,不需要推导

当默认模板参数和模板参数自动推导同时使用时(优先级从高到低):

如果可以推导出参数类型则使用推导出的类型
如果函数模板无法推导出参数类型,那么编译器会使用默认模板参数
如果无法推导出模板参数类型并且没有设置默认模板参数,编译器就会报错。
看一下下面的例子:

#include <iostream>
#include <string>
using namespace std;

// 函数模板定义
template <typename T, typename U = char>
void func(T arg1 = 100, U arg2 = 100)
{
    cout << "arg1: " << arg1 << ", arg2: " << arg2 << endl;
}

int main()
{
    // 模板函数调用
    func('a');
    func(97, 'a');
    // func();    //编译报错
    return 0;
}

程序输出的结果为:

arg1: a, arg2: d
arg1: 97, arg2: a

分析一下调用的模板函数func():

func('a'):参数T被自动推导为char类型,U使用的默认模板参数为char类型
func(97, 'a');:参数T被自动推导为int类型,U使用推导出的类型为char
func();:参数T没有指定默认模板类型,并且无法自动推导,编译器会直接报错
        模板参数类型的自动推导是根据模板函数调用时指定的实参进行推断的,没有实参则无法推导
        模板参数类型的自动推导不会参考函数模板中指定的默认参数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值