template<typename Func, typename = void> 在类模板中的应用

news2025/1/1 13:53:16

1、基础语法

在 C++ 中,template<typename Func, typename = void> 这一模板声明不仅仅限于函数模板,它在类模板中同样具有强大的应用。结合 SFINAE(Substitution Failure Is Not An Error)和 类型特征(type traits),我们可以根据类型特征(如是否可调用、是否为某种类型等)来实现不同的类特化,从而使得我们的代码更加灵活、可扩展。
在类模板中,template<typename Func, typename = void> 的基本结构类似于函数模板,但其作用是为类提供更强的类型约束和灵活性。例如:

template<typename Func, typename = void>
class MyClass {
public:
    void call(Func&& f) {
        // Generic behavior
    }
};

这里,template<typename Func, typename = void> 表示 MyClass 是一个模板类,它接受一个类型参数 Func,第二个模板参数 = void 是默认值。该类可以根据不同类型的 Func 做出不同的行为,而 = void 通常用于与 SFINAE 机制配合,决定是否允许某些特定的类型实例化该类模板。

2、类模板的默认类型参数:简化和泛化

与函数模板类似,template<typename Func, typename = void> 在类模板中的一个常见用途是通过默认类型参数简化模板声明。我们通常使用第二个类型参数 = void 来启用某些特化或重载,这通常结合 SFINAE 使用。通过这种方式,模板类在默认情况下为某些类型提供通用行为,而在遇到特定类型时可以提供特化的行为。假设我们希望在类模板 MyClass 中提供一个 call 成员函数,当 Func 是可调用类型时,执行该函数,而如果 Func 不是可调用类型,则提供默认行为,代码如下:

#include <iostream>
#include <type_traits>

template<typename Func, typename = void>
class MyClass {
public:
    void call(Func&& f) {
        std::cout << "Generic version of call" << std::endl;
    }
};

// 特化版本:当 Func 是可调用类型时
template<typename Func>
class MyClass<Func, typename std::enable_if<std::is_invocable<Func>::value>::type> {
public:
    void call(Func&& f) {
        std::cout << "Callable function version of call" << std::endl;
        f(); // 执行传入的可调用对象
    }
};

void test_func() {
    std::cout << "test_func executed!" << std::endl;
}

int main() {
    MyClass<int> obj1;
    obj1.call(42);  // 输出: Generic version of call

    MyClass<void(*)()> obj2;
    obj2.call(test_func);  // 输出: Callable function version of call
                           //        test_func executed!
}
  • 通用版本:当 Func 不是可调用类型时,MyClass<Func, typename = void> 使用默认版本的 call 函数输出 “Generic version of call”。
  • 特化版本:当 Func 是可调用类型时,我们通过 std::enable_if 和 std::is_invocable 来限制模板实例化,使得编译器选择特化版本的 call,在这种情况下,我们可以直接调用 f() 来执行传入的可调用对象。

3、SFINAE:类模板中根据类型特征选择特化

template<typename Func, typename = void> 还常常与 SFINAE 结合使用来根据类型的不同提供不同的实现。SFINAE 机制允许在类型不匹配时,编译器不报错,而是选择其他合适的模板特化或重载版本。可以使用该技术根据类型特征提供不同的成员函数,我们将使用 std::is_integral 和 std::is_floating_point 类型特征来为整数类型和浮动类型提供不同的处理方法:

#include <iostream>
#include <type_traits>

template<typename T, typename = void>
class MyClass {
public:
    void print() {
        std::cout << "Generic version: Unknown type" << std::endl;
    }
};

// 特化版本:当 T 是整数类型时
template<typename T>
class MyClass<T, typename std::enable_if<std::is_integral<T>::value>::type> {
public:
    void print() {
        std::cout << "Integer version: " << sizeof(T) << " bytes" << std::endl;
    }
};

// 特化版本:当 T 是浮动类型时
template<typename T>
class MyClass<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
public:
    void print() {
        std::cout << "Floating point version: " << sizeof(T) << " bytes" << std::endl;
    }
};

int main() {
    MyClass<int> obj1;
    obj1.print();  // 输出: Integer version: 4 bytes

    MyClass<double> obj2;
    obj2.print();  // 输出: Floating point version: 8 bytes

    MyClass<std::string> obj3;
    obj3.print();  // 输出: Generic version: Unknown type
}
  • 通用版本:对于非整数和非浮动类型,MyClass 使用通用版本的 print 成员函数。
  • 整数类型特化:当 T 是整数类型时,使用特化版本的 print,输出整数类型的大小(以字节为单位)。
  • 浮动类型特化:当 T 是浮动类型时,使用特化版本的 print,输出浮动类型的大小。

4、利用 = void 实现类型推导和重载

通过使用 template<typename Func, typename = void>,我们可以根据传入类型的特性来推导不同的行为。= void 作为一个默认模板参数可以帮助我们更好地控制模板重载和特化的匹配,尤其是在类模板中结合其他模板参数进行推导时。

#include <iostream>
#include <type_traits>

template<typename T, typename = void>
class MyClass {
public:
    void foo() {
        std::cout << "Generic version of foo" << std::endl;
    }
};

// 特化版本:当 T 是指针类型时
template<typename T>
class MyClass<T, typename std::enable_if<std::is_pointer<T>::value>::type> {
public:
    void foo() {
        std::cout << "Pointer type version of foo" << std::endl;
    }
};

int main() {
    MyClass<int> obj1;
    obj1.foo();  // 输出: Generic version of foo

    MyClass<int*> obj2;
    obj2.foo();  // 输出: Pointer type version of foo
}
  • 通用版本:对于普通类型 T,MyClass 使用通用版本的 foo 成员函数。
  • 指针类型特化:当 T 是指针类型时,MyClass 使用特化版本的 foo 成员函数。

5、结合 std::enable_if 和 std::is_same 实现类型限制

= void 还常常与 std::enable_if 和 std::is_same 等类型特征配合使用,限制模板类的实例化,提供更加灵活的行为。

#include <iostream>
#include <type_traits>

template<typename T, typename = void>
class MyClass {
public:
    void print() {
        std::cout << "Generic print" << std::endl;
    }
};

// 当 T 是 int 时,使用特化版本
template<typename T>
class MyClass<T, typename std::enable_if<std::is_same<T, int>::value>::type> {
public:
    void print() {
        std::cout << "Specialized print for int" << std::endl;
    }
};

int main() {
    MyClass<double> obj1;
    obj1.print();  // 输出: Generic print

    MyClass<int> obj2;
    obj2.print();  // 输出: Specialized print for int
}

6、总结

template<typename Func, typename = void> 在类模板中的应用,充分体现了 C++ 模板编程的灵活性。通过使用默认模板参数和与 SFINAE 相结合的机制,我们可以实现基于类型特征的模板特化和重载,使得代码更加通用、简洁且具备高度的可扩展性。

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

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

相关文章

e3 1220lv3 cpu-z分数

e3 1220lv3 双核四线程&#xff0c;1.1G频率&#xff0c;最低可在800MHZ运行&#xff0c;TDP 13W。 使用PE启动后测试cpu-z分数。 现在e3 1220lv3的价格落到69元。

Debian安装配置RocketMQ

安装配置 本次安装在/tools/rocket目录下 下载 wget https://dist.apache.org/repos/dist/release/rocketmq/5.3.1/rocketmq-all-5.3.1-bin-release.zip 解压缩 unzip rocketmq-all-5.3.1-bin-release.zip 如果出现以下报错 -bash: unzip: command not found可安装unzip工具后执…

cocos 运行时,实时查看、修改节点树

简介 cocos论坛提供的一款辅助查看、修改cocos运行时的节点树工具&#xff0c;同时也可以实时修改运行的节点树并进行修改。在此感谢大佬提供这么实用的工具。 参考链接&#xff1a;【运行时显示节点树插件】ccc-devtools悄悄更新 - Creator 2.x - Cocos中文社区 仓库链接&a…

UE(虚幻)学习(四) 第一个C++类来控制小球移动来理解蓝图和脚本如何工作

UE5视频看了不少&#xff0c;但基本都是蓝图如何搞&#xff0c;或者改一下属性&#xff0c;理解UE系统现有组件使用的。一直对C脚本和蓝图之间的关系不是很理解&#xff0c;看到一个视频讲的很好&#xff0c;我也做笔记记录一下。 我的环境是UE5.3.2. 创建UE空项目 我们创建…

记一次内存泄漏分析(待写稿)

背景 线上Flink频繁重启&#xff0c;先后排查了很多情况&#xff0c;目前在内存阶段排查&#xff0c;首先说说学到的知识 内存泄漏分析 JVM常用命令 JConsole JVisualvm 快照的这里是最有用的&#xff0c;它和jmap不同&#xff0c;jmap查找的是占用字节最多的类&#xff…

【蓝桥杯——物联网设计与开发】拓展模块5 - 光敏/热释电模块

目录 一、光敏/热释电模块 &#xff08;1&#xff09;资源介绍 &#x1f505;原理图 &#x1f505;AS312 &#x1f319;简介 &#x1f319;特性 &#x1f505;LDR &#xff08;2&#xff09;STM32CubeMX 软件配置 &#xff08;3&#xff09;代码编写 &#xff08;4&#x…

C语言从入门到放弃教程

C语言从入门到放弃 1. 介绍1.1 特点1.2 历史与发展1.3 应用领域 2. 安装2.1 编译器安装2.2 编辑器安装 3. 第一个程序1. 包含头文件2. 主函数定义3. 打印语句4. 返回值 4. 基础语法4.1 注释4.1.1 单行注释4.1.2 多行注释 4.2 关键字4.2.1 C语言标准4.2.2 C89/C90关键字&#xf…

第三百四十六节 JavaFX教程 - JavaFX绑定

JavaFX教程 - JavaFX绑定 JavaFX绑定同步两个值&#xff1a;当因变量更改时&#xff0c;其他变量更改。 要将属性绑定到另一个属性&#xff0c;请调用bind()方法&#xff0c;该方法在一个方向绑定值。例如&#xff0c;当属性A绑定到属性B时&#xff0c;属性B的更改将更新属性A…

慧集通客户案例:致远OA与熵基考勤机集成方案

本原型公司是一家专注大健康产业的综合性高新科技形实体企业&#xff0c;按照单位的战略业务布局&#xff0c;围绕“做强做优、世界一流”的目标&#xff0c;加快内外部资源整合、加强业务协同、优化资源配置&#xff0c;有序推进大健康及相关产业的有机融合&#xff0c;加快构…

SCSA: Exploring the Synergistic Effects Between Spatial and Channel Attention

摘要 https://arxiv.org/pdf/2407.05128 通道注意力和空间注意力分别为各种下游视觉任务在提取特征依赖性和空间结构关系方面带来了显著改进。通道注意力和空间注意力的结合使用被广泛认为有利于进一步提升性能&#xff1b;然而&#xff0c;通道注意力和空间注意力之间的协同作…

UE5在蓝图中使用VarestX插件访问API

在Fab中安装好VarestX免费插件 这个插件可以用来远程请求http和api等&#xff0c;返回json等格式内容 插件网址 https://www.fab.com/zh-cn/listings/d283e40c-4ee5-4e73-8110-cc7253cbeaab 虚幻里开启插件 然后网上随便搜个免费api测试一下&#xff0c;这里我找了个微博热搜…

碰一碰发视频矩阵系统源码搭建,支持OEM

一、引言 随着短视频的火爆发展&#xff0c;碰一碰发视频的矩阵系统逐渐受到关注。这种系统能够实现用户通过碰一碰设备&#xff08;如 NFC 标签&#xff09;快速触发视频的发布&#xff0c;在营销推广、互动体验等领域有着广泛的应用前景。本文将详细介绍碰一碰发视频矩阵系统…

Pandas01

文章目录 内容简介1 常用数据分析三方库2 Jupyter notebook3 Series的创建3.1 通过Numpy的Ndarray 创建一个Series3.2 通过列表创建Series 4 Series的属性和方法4.1 常用属性4.2 常用方法4.3 布尔值列表筛选部分数据4.4 Series 的运算 5 DataFrame的创建通过字典创建通过列表[元…

WebPack3项目升级webpack5的配置调试记录

文章目录 前言一、webpack3环境1.1、知识点记录1.1.1、配置解释1.1.2、webpack与sass版本对应关系1.1.3、CommonJS与ESModule1.1.4、node版本管理nvm1.1.5、sass-loader、sass与node-sass 1.2、其他1.2.1、.d.ts是什么文件1.2.2、react与types/react版本对应关系1.2.3、webpack…

plsql :用户system通过sysdba连接数据库--报错ora-01031

一、winR cmd通过命令窗口登录sys用户 sql sys/[password]//localhost:1521/[service_name] as sysdba二、输入用户名:sys as sysdba 三、输入密码:自己设的 四、执行grant sysdba to system; 再去PL/SQL连接就可以了

Quo Vadis, Anomaly Detection? LLMs and VLMs in the Spotlight 论文阅读

文章信息&#xff1a; 原文链接&#xff1a;https://arxiv.org/abs/2412.18298 Abstract 视频异常检测&#xff08;VAD&#xff09;通过整合大语言模型&#xff08;LLMs&#xff09;和视觉语言模型&#xff08;VLMs&#xff09;取得了显著进展&#xff0c;解决了动态开放世界…

药片缺陷检测数据集,8625张图片,使用YOLO,PASICAL VOC XML,COCO JSON格式标注,可识别药品是否有缺陷,是否完整

药片缺陷检测数据集&#xff0c;8625张图片&#xff0c;使用YOLO&#xff0c;PASICAL VOC XML&#xff0c;COCO JSON格式标注&#xff0c;可识别药品是否有缺陷&#xff0c;是否完整 有缺陷的标注信息&#xff1a; 无缺陷的标注信息 数据集下载&#xff1a; yolov11:https://d…

蓝桥杯速成教程{三}(adc,i2c,uart)

目录 一、adc 原理图​编辑引脚配置 Adc通道使能配置 实例测试 ​编辑效果显示 案例程序 badc 按键相关函数 测量频率占空比 main 按键的过程 显示界面的过程 二、IIC通信-eeprom 原理图AT24C02 引脚配置 不可用状态&#xff0c;用的软件IIC 官方库移植 At24c02手册 ​编辑…

第6章 图论

2024年12月25日一稿 &#x1f430;6.1 图的基本概念 6.1.1 图的定义和表示 6.1.2 图的同构 6.1.3 完全图与正则图 6.1.4 子图与补图 6.1.5 通路与回路 6.2 图的连通性 6.2.1 无向图的连通性 6.2.2 有向图的连通性 6.3 图的矩阵表示 6.3.1 关联矩阵 6.3.2 有向图的邻接矩阵…

数据库原理及应用(MySQL版-李月军)-习题参考答案

数据库原理及应用&#xff08;MySQL版&#xff09;-微课视频版 习题参考答案 习 题一 一&#xff0e;选择题 1、D 2、C 3、C 4、B 5、D 6、B 7、A 8、B 9、C 10、A 11、B 12、C 13、①A②B③C 14、①E②B 15、①B②C③B 16、B 17、A 18、D 二&#xff0e;填空题 1、文件…