首页 > 编程语言 >c++ 模板模板参数("Template Template Parameters")

c++ 模板模板参数("Template Template Parameters")

时间:2024-05-08 11:36:24浏览次数:23  
标签:容器 Container 函数 Parameters 参数 Template 类型 模板

#include <iostream>
#include <vector>
#include <list>
 
using namespace std;
 
namespace _nmsp1
{
    // T类型模板参数,代表容器中元素类型
    // Container代表的不是一个类型(不能是一个类型模板参数),而是一个类模板(类名)
    // Container不叫做类型模板参数,而叫做模板模板参数,表示这个模板参数本身又是一个模板;
    template <
        typename T,
        //typename Container = std::vector
        //template <class> class Container = std::vector        // 这就是一个名为Container(其它名字也行)的模板模板参数;
        template <typename W> typename Container = std::vector  // 另一种写法,W可以省略,
                                                                // Container如果myclass类模板中不使用也可以省略,
                                                                // 从而出现了typename后面直接接=的写法
    >
    class myclass
    {
    public:
        Container<T> myc;
 
    public:
        void func();
        myclass() // 构造函数
        {
            for (int i = 0; i < 10; ++i)
            {
                myc.push_back(i);  // 这几行代码是否正确取决于实例化该类模板时所提供的模板参数类型
            }
        }
    };
 
    template <
        typename T,
        template <typename W> typename  Container
    >
    void myclass<T, Container>::func()
    {
        cout << "good!" << endl;
    }
 
 
    //-------------------
    template <
        //.....
        template <typename W, W* point> typename Container
    >
    class myclass2
    {
        // W* m_p;  // 错误,不可以在这里使用W(W叫做模板模板参数Container的模板参数)
    };
 
    //--------------------
    template <
        //......
        // Container如果myclass类模板中不使用也可以省略,
        // 从而出现了typename后面直接接=的写法
        template <typename W> typename = std::vector 
    >
    class myclass3
    {
 
    };
}
 
// 模板模板参数
// 英文名,Template Template Parameters,即模板参数本身成为模板
//      a) int,类型,简单类型/内部类型
//      b) vector,list,是C++标准库中的容器,类模板(类名),
//              vector<int>或者list<double>就属于模板实例化的参数称为类型(类类型);
int main()
{
    _nmsp1::myclass<int, vector> myvectorobj;   // int是容器中的元素类型,vector是容器类型
    _nmsp1::myclass<double, list> mylistobj;    // double是容器中的元素类型,list是容器类型
    _nmsp1::myclass<double, list> mylistobj2;   // double是容器中的元素类型,list是容器类型
    mylistobj2.func();
}

"Template Template Parameters" 是指模板参数本身是一个模板。这种情况在 C++ 中用于定义接受其他模板作为参数的模板,通常用于实现泛型和高阶模板编程。这种概念在一些高级 C++ 模板设计和元编程场景中非常有用。

在 C++ 中,模板参数不仅可以是类型(例如 intfloat 等),也可以是整型常量、指针、引用、甚至是类模板。这些参数在 C++11 及以后版本中得到了更好的支持,特别是 C++17 及之后。

但是上面的代码是有问题的,std::vector/list 是一个模板类,它有两个模板参数:元素类型和分配器类型。因此,在使用 std::vector 作为模板参数时,你需要提供两个模板参数,而不是一个。下面是修正后的代码:

template <class T,
          template <class, class> class Contain>
class A
{
public:
    void fun()
    {
        for(int i=0; i<5; i++)
        {
            mycon.push_back(i);
        }
    }
    
    void output()
    {
        for(auto& i : mycon)
        {
            cout << i << endl;
        }
    }

private:
    Contain<T, std::allocator<T>> mycon;
};

int main()
{
    A<int, std::vector> v1;
    v1.fun();
    v1.output();
    
    return 0;
}

template <class T>
using Vector=std::vector<T,std::allocator<T>>;

template <class T,
template <class,class> class Contain>
class A
{
public:
 void fun()
 {
   for(int i=0;i<5;i++)
   {
     mycon.push_back(i);
   }
 }
 void output()
 {
   for(auto& i:mycon)
   {
     cout<<i<<endl;
   }
 }

private:
  Contain<T,std::allocator<T>> mycon;
};
int main()
{
  A<int,std::vector> v1;
  v1.fun();
  v1.output();
   
}

当然:也可以用于函数

当你尝试将模板类作为函数的形参时,需要指定模板参数。如果你想要灵活地传递不同类型的容器作为函数参数,可以使用函数模板。下面是一个示例:

#include <iostream>
#include <vector>
#include <list>

using namespace std;

// 使用函数模板作为参数
template <template <class, class> class Contain, class T>
void printContainer(const Contain<T, std::allocator<T>>& container)
{
    for(const auto& element : container)
    {
        cout << element << " ";
    }
    cout << endl;
}

int main()
{
    vector<int> vec = {1, 2, 3, 4, 5};
    list<double> lst = {1.1, 2.2, 3.3, 4.4, 5.5};

    // 使用函数模板打印不同类型的容器
    printContainer(vec);
    printContainer(lst);
    
    return 0;
}

当然你可以更灵活:这种方式使用了更通用的模板形式,即将 printContainer 函数改为接受任何类型的容器,而不是特定类型的模板容器。这种方式的优势是更加灵活,可以接受任何类型的容器作为参数,而不仅仅局限于特定的模板容器。因此,你可以将任何类型的容器传递给该函数,而不需要显式地指定模板参数。

#include <iostream>
#include <vector>
#include <list>

using namespace std;

template <class T>
void printContainer(const T& container)
{
    for(const auto& element : container)
    {
        cout << element << " ";
    }
    cout << endl;
}

int main()
{
    vector<int> vec = {1, 2, 3, 4, 5};
    list<double> lst = {1.1, 2.2, 3.3, 4.4, 5.5};

    // 使用函数模板打印不同类型的容器
    printContainer(vec);
    printContainer(lst);
    
    return 0;
}

这种方式的缺点是,当你使用函数模板时,你失去了对特定容器类型的控制,因此在函数内部,你可能无法依赖于特定容器提供的特定成员函数或特性。因此,需要在编写函数模板时更加小心谨慎,确保它适用于各种可能的容器类型。

这两种方式的区别主要在于函数参数的类型和函数的灵活性:

  1. 指定模板参数的方式:

    • 第一种方式中,函数模板 printContainer 接受一个模板类 Contain 和一个元素类型 T 作为参数,允许你显式地指定容器的模板参数类型。
    • 第二种方式中,函数模板 printContainer 接受一个模板参数 T,而函数参数类型是模板参数 T 的实例化,即任何类型的容器,因此不需要显式指定容器的模板参数类型。
  2. 函数的灵活性:

    • 第一种方式具有更大的灵活性,因为你可以选择性地指定容器的模板参数类型。这使得你可以更具体地控制函数接受的容器类型。
    • 第二种方式则更加通用和灵活,因为它可以接受任何类型的容器作为参数,无需显式指定容器的模板参数类型。这种方式适用于更广泛的情况,但在函数内部可能需要更多的类型检查和处理。

因此,选择哪种方式取决于你的需求和偏好。如果你需要对容器类型进行更精确的控制,或者希望提供更具体的接口,可以选择第一种方式。如果你需要更通用的函数,能够接受各种类型的容器,可以选择第二种方式。

 

标签:容器,Container,函数,Parameters,参数,Template,类型,模板
From: https://www.cnblogs.com/bwbfight/p/18179327

相关文章

  • P3383 【模板】线性筛素数
    原题链接题解关键因素:任何合数都可以分为最小质数乘上另外一个数code#include<bits/stdc++.h>usingnamespacestd;vector<int>ans;intmain(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);intn;cin>>n;vector<int>vis(n+5,0);......
  • AlmaLinux 9.3 x86_64 OVF (sysin) - VMware 虚拟机模板
    AlmaLinux9.3x86_64OVF(sysin)-VMware虚拟机模板由社区提供的免费Linux操作系统,RHEL二进制兼容发行版。请访问原文链接:AlmaLinux9x86_64OVF(sysin)-VMware虚拟机模板,查看最新版。原创作品,转载请保留出处。作者主页:sysin.orgAlmaLinuxrelease9.3(Shamroc......
  • 代理 mitmproxy config.yaml 模板 使用笔记(二)
    代理mitmproxyconfig.yaml模板使用笔记(二)mitmproxyconfig.yaml模板使用mitmproxy可能需要用到config.yaml来批量配置参数目录config.yaml文件所在位置config.yaml配置模板文件位置配置文件默认读取路径:~/.mitmproxy/config.yaml,见配置项:confdir:'~/.mitmpro......
  • 【GD32】---- 移植工程模板
    1新建模板文件夹新建一个名叫03_GD32TemplateProject的文件夹,用于建造工程模板2移植官方库文件在模板文件夹里新建5个文件夹,分别存放官方库文件和系统驱动文件01_main存放main函数02_Startup存放系统启动文件03_System存放官方的系统文件04_Firmware_PeripheralD......
  • 【 攻防实操系列+漏洞复现 】-- Jinja2 SSTI模板注入
    框架:python---Flask描述:Flask是一个使用Python编写的轻量级Web应用框架。其WSGI工具箱采用Werkzeug,模板引擎则使用Jinja2漏洞复现:Jinja2SSTI模板注入使用vulhub靶场,启动环境先进入容器看一下web服务的代码,得出参数值为name,且可控判断是否存在ssti漏洞,输入:?name={{1*9}},......
  • RestTemplate返回结果乱码的两种解决方案
    以下代码调用某接口时出现乱码:HttpHeadershttpHeaders=newHttpHeaders();httpHeaders.add("Content-Type","application/json;charset=utf-8");org.springframework.http.HttpEntity<String>httpEntity=neworg.springframework.http.HttpEntity<......
  • luogu P6329 【模板】点分树 | 震波
    //【模板】点分树|震波//https://www.luogu.com.cn/problem/P6329#include<bits/stdc++.h>#definedebug(a)cerr<<"Line:"<<__LINE__<<""#a<<endl#defineprint(a)cerr<<#a"="<<(a)<<endl#d......
  • git使用模板编辑commit message
    创建commitmessage模板1.创建一个名为commit.template的模板文件:[problemdescription]:[rootcause]:[change]:[changetype]:[sideeffects]:[reviewer]:[selftest]:[testcase]:2.在git中设置模板路径:只在当前git管理的代码中使用此模板,在当前......
  • P3811 【模板】模意义下的乘法逆元
    题目:P3811【模板】模意义下的乘法逆元【模板】模意义下的乘法逆元题目背景这是一道模板题题目描述给定$n,p$求$1\simn$中所有整数在模$p$意义下的乘法逆元。这里$a$模$p$的乘法逆元定义为$ax\equiv1\pmodp$的解。输入格式一行两个正整数$n,p$。输出格式......
  • Verilog插件:补全模块实例模板
    https://mp.weixin.qq.com/s/tiaXdddID5-hxPtJZOvm8gIntellijIDEA插件VerilogLanguageSupport(插件链接),v2024.2.0版本特性。     https://mp.weixin.qq.com/s/tiaXdddID5-hxPtJZOvm8g ......