泛型编程-常用模板

例举C++11 常用模板

一.变参模板

        当我们需要处理不定数量的参数时,C++的变参模板(variadic templates)提供了一种灵活的解决方案。变参模板允许我们定义接受任意数量参数的函数或类模板。

        变参模板主要分为三部分:

        模板形参包(固定类型模板形参包、类型模板形参包、模板模板形参包)、函数形参包、形参展开使用。

1. 变参数模板的基础-模板形参包
1.1 非类型模板形参包(c++17引入)

        非类型(固定)模板形参包的主要用途是在编写通用代码时,能够接受任意数量的非类型参数,并对它们进行处理。这样可以实现更灵活的模板编程,提高代码的复用性和可扩展性。

使用语法:

template<类型 ... args>

 注意:这个类型是有限制的,只能是整型、指针、引用

使用折叠语法

template <int... Values>
constexpr int sum() {
    return (Values + ...);
}

int main()
{
    int result = sum<1, 2, 3, 4, 5>();
    std::cout << result << std::endl;
}
1.2 类型模板形参包

类型模板形参包语法:

typename|class ... Args

使用: 

#include <iostream>
#include <memory>

using namespace std;

int sum()  //没有参数的时候
{
    return 0;
}

template<typename T, typename... Args>  
auto sum(T first, Args... args)
{
    return (first) + sum(args...);
}

int main()
{
    cout<<"sum:"<<sum(1,2,3,4,5)<<endl;
    return 0;
}

typename... Args:这是一个模板参数包(template parameter pack)的语法,用于接受任意数量的类型参数,并将它们打包成一个参数包 Args

Args... rest:这是一个函数参数包(function parameter pack)的语法,用于接受任意数量的函数参数,并将它们打包成一个参数包 rest

rest...:这是一个展开语法(unpacking syntax),用于将参数包 rest 展开为一系列参数。

在示例中,Args 表示一组类型参数,

                  rest 表示一组函数参数,

                  rest... 将参数包 rest 展开为一系列参数,然后作为新的参数传递给函数。

 1.3 模板模板形参包

        待补充。

2.模板形参包延申-函数形参包

函数形参包的语法:

Args ... args

Args...代表形参包类型,这个类型就是模板形参包里面声明的类型,args就是函数的形参名称了,是可以自定义的。 

        除了非类型的模板形参包因为类型固定且是具体的值,不能作为函数形参包以外,类型模板形参包和模板模板形参包因为声明的都是类型,所以他们是可以用作函数形参的类型的。

        上述已经举例,不做过多说明。

3.模板形参包的展开方法 

形参包展开语法:

模式 ...

二.别名模板-using

        using 关键字在 C++11 之前,using 关键字主要用于类型别名的声明。例如:

typedef int myInt;
using myInt = int;

        在 C++11 中,using 关键字引入了新的类型别名声明语法,包括别名模板、类型别名模板、

特化别名模板、特化类型别名mo'b

#include <iostream>
#include <vector>

// 别名模板
template <typename T>
using myAlias = std::vector<T>;

// 类型别名模板
template <typename T>
struct myTypeAlias {
    using type = std::vector<T>;
};

// 特化别名模板
template <>
using myAlias<int> = std::vector<int>;

// 特化类型别名模板
template <>
struct myTypeAlias<int> {
    using type = std::vector<int>;
};

int main() {
    myAlias<double> myVector1;  // 使用别名模板
    myVector1.push_back(1.23);
    myVector1.push_back(4.56);
    std::cout << "Size of myVector1: " << myVector1.size() << std::endl;

    typename myTypeAlias<double>::type myVector2;  // 使用类型别名模板
    myVector2.push_back(7.89);
    myVector2.push_back(0.12);
    std::cout << "Size of myVector2: " << myVector2.size() << std::endl;

    myAlias<int> myVector3;  // 使用特化的别名模板
    myVector3.push_back(1);
    myVector3.push_back(2);
    std::cout << "Size of myVector3: " << myVector3.size() << std::endl;

    typename myTypeAlias<int>::type myVector4;  // 使用特化的类型别名模板
    myVector4.push_back(3);
    myVector4.push_back(4);
    std::cout << "Size of myVector4: " << myVector4.size() << std::endl;

    return 0;
}

三.tuple 类模板

        在C++11 引用std::tuple 类模板,它是一个通用的元组类,可以存储多个不同类型的值。需要注意的是,std::tuple 是一个不可变的数据结构,一旦创建后,其元素的值是不可修改的。

#include <iostream>
#include <memory>
#include <tuple>

using namespace std;

struct MyStruct {
    int value;
    double weight;
    string str1;
};

using MyCustomStruct = MyStruct;

int main()
{
    //通过get读取
    tuple<int, double, string> mytuple(1,99.9,"hello");
    cout<<"mytuple.get:"<<get<0>(mytuple)<<endl;
    cout<<"mytuple.get:"<<get<1>(mytuple)<<endl;
    cout<<"mytuple.get:"<<get<2>(mytuple)<<endl;
    cout<<"sizeof(tuple)"<<sizeof(mytuple)<<endl;  //48
    cout<<"sizeof(int)"<<sizeof(get<0>(mytuple))<<endl; //4
    cout<<"sizeof(double)"<<sizeof(get<1>(mytuple))<<endl; //8 
    cout<<"sizeof(string)"<<sizeof(get<2>(mytuple))<<endl; //32
    cout<<"sizeof(MyStruct)"<<sizeof(MyCustomStruct)<<endl; //48

    //通过 结构化绑定解包 tuple 中的值
    auto[intVal, douVal, strVal] = mytuple;
    cout<<"intVal:"<<intVal<<endl;
    cout<<"douVal:"<<douVal<<endl;
    cout<<"strVal:"<<strVal<<endl;
    //赋值
    auto mytuple2 = make_tuple(99, get<2>(mytuple), "nihao");
}

四.bind类模板

         std::bind 是 C++ 标准库中的一个函数模板,用于创建函数对象(也称为绑定器),将参数绑定到函数中。它的使用场景包括:

  •  绑定函数对象:std::bind可以将一个函数对象与其参数绑定,创建一个新的可调用对象。这样,我们可以在稍后的时间点调用这个可调用对象,而不需要再次提供参数。这对于延迟执行函数或将函数作为参数传递非常有用。、
  • 重排参数顺序:std::bind可以通过重新排列参数的顺序,将函数的参数与绑定的参数进行匹配。这使得我们可以在调用时以不同的顺序提供参数,而不必更改函数的定义。
  • 固定部分参数:std::bind可以将函数的部分参数固定下来,而不需要提供完整的参数列表。这样,我们可以创建一个新的函数对象,该对象只需要提供剩余的参数即可完成调用。
  • 占位符参数:std::bind使用std::placeholders::_1std::placeholders::_2等占位符参数,可以在绑定函数对象时指定参数的位置。这使得我们可以在调用时动态地提供参数,而不需要提前确定参数
1.bind绑定非成员函数
#include <iostream>
#include <functional>

using namespace std;

int sum(int a, int b)
{
    return a + b;
}

int main()
{
    auto func = std::bind(sum, 1, placeholders::_1);
    cout<<"sum:"<<func(2)<<endl;
}
2.bind绑定成员函数 
#include <iostream>
#include <functional>

using namespace std;

class MyClass {
public:
    int sum(int a, int b) 
    {
        return a+ b;
    }
};

int main()
{
    MyClass obj;
    auto func = std::bind(&MyClass::sum, &obj, 1, placeholders::_1);
    cout<<"sum:"<<func(2)<<endl;
}
3.bind函数使用注意
  • bind函数无法绑定一个重载函数的参数,必须显示的绑定重载函数版本
//有这样的重载函数
int good(int);
double good(double);
auto result = std::bind(good,_1);      //错误形式,不知道调用哪一个good函数
//正确的做法,但是比较复杂
auto result_1 = std::bind(double(*)(double)good, _1); 
//这是更好的方式
auto result_2 = std::bind<double>(good, _1);   //指定函数的返回类型

五.function类模板

        std::function是一个通用的函数封装器,可以用来存储、复制和调用任何可调用对象(函数、函数指针、成员函数指针、函数对象等)。它可以用于实现回调机制、函数参数传递等。

        std::function不管其实例类型是什么样的,其调用形式是一样的,如下:

返回值类型(实参1,实参2,实参3...)

使用方法(列举所有函数调用方法):

#include <iostream>
#include <functional>

using namespace std;

typedef function<int(int)> Functional;

int funcValue(int x) 
{
    return x;
}

//仿函数
class Functor
{
public:
   int operator()(int a)
   {
       return a;
    }
};

//类的成员函数和静态函数
class Func
{
public:
    int func(int a)
    {
        return a;
    }
    static int staticFunc(int a)
    {
        return a;
    }
};

int main()
{
    //普通函数调用
    cout<<"value:"<<funcValue(1)<<endl;
    //封装普通函数
    Functional obj = funcValue;
    cout<<"obj.value:"<<obj(2)<<endl;
    //lamda表达式
    auto lambObj = [](int a)->int{return a;};
    cout<<"lambObj.value"<<lambObj(3)<<endl;
    //仿函数
    Functor obj1;
    cout<<"obj1.value:"<<obj1(4)<<endl;
    //类成员函数
    Func fun;
    cout<<"func.value:"<<fun.func(5)<<endl;
    //类静态成员函数
    cout<<"staticFunc.value:"<<Func::staticFunc(6)<<endl;
    //通过bind绑定
    auto bindfun = bind(&Func::func, &fun, placeholders::_1);
    cout<<"bindfun.value:"<<bindfun(7)<<endl;
}

六.智能引用

        智能引用是一种用于管理资源的对象。它们提供了对资源的安全访问,并确保资源在不再需要时被正确释放,使用智能引用的好处:

  1. 包装你给的对象引用
  2. 传参数时, 消除复杂对象的拷贝代价
  3. 不可拷贝对象转换为可拷贝对象(noncopyable, singleton之类的)

对于第二点:

#include <iostream>
#include <functional>

using namespace std;

template<class T>
class ref_wra
{
public:
    explicit ref_wra(T &_t):t_(&_t){}
    operator T&() const{return *t_;}  //将对象转换为T&的引用  

    T& get() const{return *t_;}
    T* get_ptr() const{return t_;}

private:
    T *t_;
};


void add(int& num) {
    num++;
}

int main()
{
    int dight =  10;
    ref_wra<int> ref(dight); //隐式转换operator T&()

    cout<<"1.通过隐式转换,使用引用访问原始对象:"<<ref<<endl;

    int value = ref; //隐式转换operator T&()
    cout<<"2.通过隐式转换,使用引用访问原始对象:"<<value<<endl;

    ref.get() = 11;
    cout<<"3.访问原始对象:"<<ref<<endl;

    int *ptr = ref.get_ptr();
    cout<<"4.内部维护指针:"<<ref<<endl;

    add(ref);
    cout<<"5.通过传引用:"<<ref<<endl;

    return 0;
}

相关推荐

  1. 编程-模板

    2024-01-09 23:50:03       46 阅读
  2. C++ 编程 模板

    2024-01-09 23:50:03       37 阅读
  3. C++ 模板编程详解

    2024-01-09 23:50:03       29 阅读
  4. C++模板编程编程的强大工具

    2024-01-09 23:50:03       21 阅读
  5. GO - 编程

    2024-01-09 23:50:03       41 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-09 23:50:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-09 23:50:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-01-09 23:50:03       87 阅读
  4. Python语言-面向对象

    2024-01-09 23:50:03       96 阅读

热门阅读

  1. 怎么形象化理解线程

    2024-01-09 23:50:03       54 阅读
  2. alist重置密码

    2024-01-09 23:50:03       75 阅读
  3. PCL 点云八叉树体素搜索

    2024-01-09 23:50:03       59 阅读
  4. 服务器常见问题以及处理方案

    2024-01-09 23:50:03       57 阅读
  5. DRM-VAE

    DRM-VAE

    2024-01-09 23:50:03      52 阅读
  6. Linux中yum命令工作原理

    2024-01-09 23:50:03       43 阅读