C++模板基础(八)

news2024/9/30 11:31:21

数值模板参数与模板模板参数
● 模板可以接收(编译期常量)数值作为模板参数
– template class Str;

template<int a>
int fun(int x)
{
    return x + a;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    std::cout << fun<3>(5) << std::endl;

    return a.exec();
}

在这里插入图片描述

– template <typename T, T value> class Str;

template<typename T, T a>
int fun(int x)
{
    return x + a;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    std::cout << fun<int, 3>(5) << std::endl;

    return a.exec();
}

– (C++ 17) template class Str;

template<auto a> //'auto' not allowed in template parameter until C++17
int fun()
{
    
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    std::cout << fun<3>() << std::endl;
    std::cout << fun<true>() << std::endl;

    return a.exec();
}

– (C++ 20) 接收字面值类对象与浮点数作为模板参数

template<float a> //A non-type template parameter cannot have type 'float' before C++20
int fun()
{
    
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    std::cout << fun<3.14f>() << std::endl;
    
    constexpr float x = 10000 - 10000 + 3.14;
    fun<x>();
    
    constexpr float x2 = 10000 - 3.14 + 10000;
    fun<x2>();

    return a.exec();
}

● 目前 clang 12 不支持接收浮点数作为模板参数
● 接收模板作为模板参数
– template <template class C> class Str;
– (C++17) template <template typename C> class Str;

template<typename T>
class C
{
    public:
     void show()
     {
        std::cout << "template<typename T> class C void show()\n";
     }
};

template<template<typename T> class T2>
//template<template<typename T> typename T2> //Since C++17
void fun()
{
    T2<int> tmp;
    std::cout << "template<template<typename T> class T2> void fun() T1<int> tmp\n";
    tmp.show();
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    fun<C>();

    return a.exec();
}

在这里插入图片描述

– C++17 开始,模板的模板实参考虑缺省模板实参( clang 12 支持程度有限)

template<typename T>
class C
{
    public:
     void show()
     {
        std::cout << "template<typename T> class C void show()\n";
     }
};

template<typename T, typename T2>
class C2
{
    public:
     void show()
     {
        std::cout << "template<typename T, typename T2> class C2 void show()\n";
     }
};

template<template<typename T, typename T2> class C3>
//template<template<typename T> typename T2> //Since C++17
void fun()
{
    C2<int, double> tmp;
    std::cout << "template<template<typename T, typename T2> class C3> void fun() C2<int, double> tmp\n";
    tmp.show();
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    fun<C2>();

    return a.exec();
}

在这里插入图片描述

template<typename T>
class C
{
    public:
     void show()
     {
        std::cout << "template<typename T> class C void show()\n";
     }
};

template<typename T, typename T2 = int>
class C2
{
    public:
     void show()
     {
        std::cout << "template<typename T, typename T2 = int> class C2 void show()\n";
     }
};

template<template<typename> typename T2>
void fun()
{
    C2<int, double> tmp;
    std::cout << "template<template<typename> typename T2> void fun() C2<int, double> tmp\n";
    tmp.show();
}

template<>
void fun<C2>() //OK
{

}

● Str 是否支持?

别名模板与变长模板
● 可以使用 using 引入别名模板
– 为模板本身引入别名

template<typename T>
using MyType = T;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int val = 5;
    MyType<int> x = val;
    std::cout << x <<std::endl;

    return a.exec();
}

在这里插入图片描述

template<typename T>
using MyPointer = T*;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int val = 5;
    MyPointer<int> x = &val;
    std::cout << x << '\n' << *x <<std::endl;

    return a.exec();
}

在这里插入图片描述

– 为类模板的成员引入别名

template<typename T>
struct B
{
    using TP = T*;
};
template<typename T>
using MyPointer = typename B<T>::TP;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int val = 5;
    MyPointer<int> x = &val;
    std::cout << x << '\n' << *x <<std::endl;

    return a.exec();
}

– 别名模板不支持特化,但可以基于类模板的特化引入别名,以实现类似特化的功能

template<typename T>
using MyPointer = T*;

template<> //Explicit specialization of alias templates is not permitted
using MyPointer<int> = int&;
template<typename T>
struct B
{
    using type = T*;
};

template<>
struct B<int>
{
    using type = int&; //可以基于类模板的特化引入别名
};

template<typename T>
using MyPointer = typename B<T>::type;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    float val = 3.14;
    MyPointer<float> x = &val;
    std::cout << x << '\n' << *x << std::endl;

    return a.exec();
}

在这里插入图片描述
● 注意与实参推导的关系

template<typename T>
using M = T*;

template<typename T>
void fun(M<T> input) //等价于fun(T* input),于是可以进行模板实参推导
{
    std::cout << "template<typename T> void fun(M<T> input): " << *input;
}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int x = 2;
    fun(&x);

    return a.exec();
}

在这里插入图片描述

template<typename T>
struct B //如果入参是一般的类型比如int, float, double,则使用一般的类型作为此模板的T的值
{
    using type = T*;
};

template<typename T>
struct B<T*> //template<typename T> struct B的一个特化。如果入参是一般类型的指针比如int*, float*, double*,则使用一般类型的指针作为此模板的T的值
{
    using type = T*;
};

template<typename T>
using M = typename B<T>::type;

template<typename T>
void fun(M<T> input) //等价于fun(typename B<T>::type input),不能确定T的类型,fun(&x)不能进行模板实参推导
{
    std::cout << "template<typename T> void fun(M<T> input): " << *input;
}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int x = 2;
    fun(&x); //Error: No matching function for call to 'fun', candidate template ignored: couldn't infer template argument 'T'

    return a.exec();
}

● 变长模板( Variadic Template )
– 变长模板参数与参数包

template<int... a>
void fun()
{
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    fun<1, 2, 3>(); //OK

    return a.exec();
}
template<typename... a>
void fun()
{
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    fun<int, char, double>(); //OK

    return a.exec();
}
template<typename... T>
void fun(T... args)
{
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    fun<int, char, double>(3, 'c', 3.14); //OK

    return a.exec();
}

– 变长模板参数可以是数值、类型或模板
– sizeof… 操作

template<typename... T>
void fun(T... args)
{
    std::cout << sizeof...(T) << std::endl; //输出等同于std::cout << sizeof...(args) << std::endl;,意为形参包里有多少个类型,而非底层的字节数
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    fun(3, 'c', 3.14);

    return a.exec();
}

在这里插入图片描述

– 注意变长模板参数的位置

template<typename... T>
class C;

template<typename T1, typename T2>
class B;

template<typename... T, typename T2>
class B<C<T...>, T2>
{

};

包展开与折叠表达式
● (C++11) 通过包展开技术操作变长模板参数

template<typename... T>
void fun(T... args)
{

}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    
    fun<int, double, char>(3, 5.3, 'c'); //T... args展开成int, double, char
    return a.exec();
}

– 包展开语句可以很复杂,需要明确是哪一部分展开,在哪里展开

template<class... Us>
void f(Us... pargs) {}
 
template<class... Ts>
void g(Ts... args)
{
    f(&args...); // “&args...” is a pack expansion
                 // “&args” is its pattern
}
 
g(1, 0.2, "a"); // Ts... args expand to int E1, double E2, const char* E3
                // &args... expands to &E1, &E2, &E3
                // Us... pargs expand to int* E1, double* E2, const char** E3
template<typename...>
struct Tuple {};
 
template<typename T1, typename T2>
struct Pair {};
 
template<class... Args1>
struct zip
{
    template<class... Args2>
    struct with
    {
        typedef Tuple<Pair<Args1, Args2>...> type;
        // Pair<Args1, Args2>... is the pack expansion
        // Pair<Args1, Args2> is the pattern
    };
};
 
typedef zip<short, int>::with<unsigned short, unsigned>::type T1;
// Pair<Args1, Args2>... expands to
// Pair<short, unsigned short>, Pair<int, unsigned int> 
// T1 is Tuple<Pair<short, unsigned short>, Pair<int, unsigned>>
 
// typedef zip<short>::with<unsigned short, unsigned>::type T2;
// error: pack expansion contains parameter packs of different lengths

● (C++17) 折叠表达式

void fun()
{

}
template<typename U, typename... T>
void fun(U u, T... args)
{
    std::cout << u << '\n';
    fun(args...);
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    fun(3, 5.3, 'C', "C++ Paramenter-Pack");

    return a.exec();
}

包展开

– 基于逗号的折叠表达式应用

template<typename... T>
void fun(T... args)
{
    ((std::cout << args << '\n'),...); //OK Since C++17
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    fun(3, 5.3, 'C', "C++ Paramenter-Pack");
    //((std::cout << args << '\n'),...);被处理成
    //std::cout << 3 << '\n', std::cout << 5.3 << '\n', std::cout << 'C' << '\n', std::cout << "C++ Paramenter-Pack" << '\n',逗号是右结合的
    //等价于
    //(std::cout << 3 << '\n', (std::cout << 5.3 << '\n', (std::cout << 'C' << '\n', (std::cout << "C++ Paramenter-Pack" << '\n'))))

    return a.exec();
}

– 折叠表达式用于表达式求值,无法处理输入(输出)是类型与模板的情形

参考
深蓝学院:C++基础与深度解析
cppreference : parameter_pack
cppreference : fold

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/429204.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

相机SD卡无法读取提示格式化 相机SD卡无法读取怎么修复

相机SD卡中储存着的照片和视频&#xff0c;承载着我们美好的回忆。因为相机SD卡的容量有限&#xff0c;我们会定期对SD卡中的数据进行云盘备份&#xff0c;然后清理相机SD卡中的数据。在打开相机SD卡时&#xff0c;可能会遇到SD卡无法读取的情况。那么&#xff0c;相机SD卡无法…

Umi‘s Friends 冠名 VC MeetUP 酒会,圆满举办!

香港加密新政的整体目的是令虚拟资产交易明确化和合法化&#xff0c;通过不断完善的监管框架&#xff0c;促进香港虚拟资产行业的可持续和负责任地发展。在加强合规和持牌经营的监管思路下&#xff0c;长期审慎合规经营的老牌机构和项目&#xff0c;显然将获得先发优势。随着香…

开放式蓝牙耳机哪个好,分享几款舒适性高的开放式蓝牙耳机

开放式耳机的兴起是近几年来才出现的新概念&#xff0c;开放式耳机也是近几年来才开始流行起来&#xff0c;在我看来开放式耳机的兴起是科技进步的产物。随着蓝牙耳机技术和设备的发展&#xff0c;蓝牙耳机也越来越普及&#xff0c;但是也给用户带来了很多困扰。而开放式耳机就…

前端学习:HTML链接

目录 一、HTML超链接&#xff08;链接&#xff09; 二、HTML链接语法 三、target属性 target属性值展示 四、name属性 五、补充 关于创建电子邮件链接时如何发送邮件内容 在进行抄送时&#xff0c;需要使用关键字&#xff1a;cc 在进行密送时&#xff0c;需要使用关键字&a…

2.rabbitmq-linux安装

目录 一.环境准备 二.安装 一.环境准备 1.RabbitMQ版本 和 Erlang 版本兼容性关系 https://www.rabbitmq.com/which-erlang.html 2.官方安装包下载地址 【erlang下载地址】&#xff1a;https://github.com/rabbitmq/erlang-rpm/releases/tag/v21.3.1【rabbitmq下载地址】&a…

初识视觉SLAM(视觉SLAM十四讲ch1~ch2的收获与总结)

视觉SLAM14讲ch1和ch2的学习视觉SLAM14讲ch1和ch2的学习前言&#xff1a;一、SLAM是什么二、视觉SLAM14讲学习前的基础三、初步了解1. 小萝卜的例子2. 了解一些视觉SLAM的框架3. 一些数学问题的表述视觉SLAM14讲ch1和ch2的学习 前言&#xff1a; 开始学习视觉SLAM&#xff0c…

MMDetection 3.x 自定义数据集

最近在调研目标检测方面的技术实现&#xff0c;发现关于 MMDetection 自定义数据集的文章&#xff0c;多是就 2.x 版本进行描述的&#xff0c;而关于 3.x 版本的则比较少。有些文章在制作COCO数据集的时候&#xff0c;需要修改多处源代码&#xff0c;而这是没有必要的。本文主要…

【论文阅读】PureGaze

复现论文 PureGaze PureGaze Overview 这篇文章在purify的角度重新定义了gaze estimation的这个问题。 对提纯问题的定义 基于提纯的思想&#xff0c;可以把 gaze estimation 的问题定义为 g F( E( I ) )。 其中&#xff0c;E 是一个特征提取的函数&#xff0c;F 是一个回…

Java中的null总结

日常工作&#xff0c;遇见几次null的语法报错&#xff0c;整理以下Java中null&#xff1a; &#x1f341; null是一个关键字&#xff0c;对大小写敏感&#xff0c;像public、static… &#x1f341; null是所有引用数据类型的默认值&#xff08;int默认0、boolean默认false…)…

HTB-Jeeves

HTB-Jeeves信息收集80端口50000端口![在这里插入图片描述](https://img-blog.csdnimg.cn/5824bf345bc040ee9e449bebeade9495.png)开机kohsuke -> Administrator信息收集 80端口 ask jeeves是一款以回答用户问题提问的自然语言引擎&#xff0c;面对问题首先查看数据库里是否…

耳机输出电路中的耦合电容设计

分析耳机输出电路。 因为其中的输出耦合电容有6个这么多&#xff0c;有点奇怪。 耳机输出电路的实物外观长这样&#xff1a; 音频解码芯片&#xff08;型号WM8988&#xff09;输出音频信号&#xff0c;经过6个耦合电容&#xff0c;最终在耳机接口输出&#xff1a; 关键看靠近…

我的世界 为何用java开发?

mc用java开发就很好滴说明了一点编程语言本身只是个工具工具的意义在于被使用&#xff0c;老外搞这些工具&#xff0c;都带有一个明确的目的性&#xff0c;就是我要做什么然后再来看&#xff0c;我们怎么用手头上的工具将其实现。 mc的开发人员最早就是一个普通的java程序员&a…

GloVe词向量自定义函数实现词向量降维

TEXT.build_vocab(train_data, max_size10000, vectorsglove.6B.100d) LABEL.build_vocab(train_data) pretrained_embedding TEXT.vocab.vectors上面代码加载了glove.6B.100d词向量&#xff0c;假设我需要设计一个函数&#xff0c;将词向量长为100映射到长为50&#xff0c;这…

在Ubuntu20.04下安装Autoware.universe和Carla并进行联合仿真

在Ubuntu20.04下安装Autoware.universe和Carla并进行联合仿真一、安装Carla0.9.13二、安装 UnrealEngine 4.26三、安装Autoware.universe四、设置 OpenPlanner五、运行Carla和Autoware一、安装Carla0.9.13 1、进入Carla 的官方 github 页面&#xff0c;找到0.9.13版本 https:/…

代码随想录算法训练营第五十八天-单调栈1|739. 每日温度 496.下一个更大元素 I

739. Daily Temperatures public class DailyTemperatures {//暴力解法public int[] dailyTemperatures(int[] T){int length T.length;int[] result new int[length];for(int i 0; i < length; i){int current T[i];if(current < 100){for(int j i 1; j < len…

C++语法(13)---- 模拟实现priority_queue

C语法&#xff08;12&#xff09;---- 模拟实现queue和stack_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/130068637 目录 1.使用 2.模拟实现 1.数据元素 2.数据建立 3.函数实现 4.向上调整和向下调整 3.仿函数&#xff08;函数对象&…

【马蹄集】第五周作业

第五周作业 目录MT2030 邮箱地址MT2039 换换换MT2040 银行账户MT2041 三角形的个数MT2046 巨大的错误MT2030 邮箱地址 难度&#xff1a;钻石    时间限制&#xff1a;1秒    占用内存&#xff1a;128M 题目描述 一个地址由 <username><hostname>[/resource] …

DAY 34 正则表达式

正则表达式 REGEXP&#xff1a; Regular Expressions&#xff0c;由一类特殊字符及文本字符所编写的模式&#xff0c; 其中有些字符&#xff08;元字符&#xff09;不表示字符字面意义&#xff0c;而表示控制或通配的功能&#xff0c; 类似于增强版的通配符功能&#xff0c;但…

day13 信号机制 (上)

目录 信号的概念 信号的发送和定时器 信号的函数 定时器函数 信号的捕捉 信号的概念 概念&#xff1a; 信号是软件层次上对中断机制的一种模拟&#xff0c;是一种异步通信方式&#xff0c;所有信号的产生及处理都是有内核完成的。 信号的产生&#xff1a; 1、按键产生…

Excel常用函数公式20例

目录 一、【IF函数条件判断】 二、【多条件判断】 三、【条件求和】 四、【多条件求和】 五、【条件计数】 六、【多条件计数】 七、【条件查找】 八、【多条件查找】 九、【计算文本算式】 十、【合并多个单元格内容】 十一、【合并带格式的单元格内容】 十二、…