日志打印中对容器(包括多级容器)的通用输出

        在日志打印中,往往有打印一个数组、集合等容器中的每个元素的需求,这些容器甚至可能嵌套起来,如果每个地方都用for循环打印,将会特别麻烦。基于这种需求,作者尝试实现一个通用的打印函数SeqToStr(),将容器序列化。

通用打印函数

        首先这个函数需要接收这个容器arr,然后接收一个打印函数的回调func,形式如下:

template <typename Iterable, typename PrintFunc>
std::string SeqToStr(const Iterable& arr, PrintFunc&& func) {std::stringstream ss;ss << '[';for (auto&& i : arr) func(ss, i) << ",";auto ret_str = ss.str();if (ret_str.length() == 1) {return std::move(ret_str += ']');} else {ret_str.back() = ']';return std::move(ret_str);}
}

        每个元素被逗号隔开,所有元素被方括号框住。

一级容器

        当然,每次调用都写一个func也是很难用的,所以对于一级容器,可以写一个重载,用默认的打印函数:


inline std::string SeqToStr(const Iterable& arr) {return SeqToStr(arr, [](auto& ss, auto&& ele) -> decltype(auto) { return ss << ele; });
}
// p

        ss是一个支持流操作符<<(stringstream,basic_ostream等)的参数,返回值decltype(auto)防止<<返回的引用被当做值传回,实际上basic_ostream不支持复制,所以不显式指定返回值类型推导的话,编都编不过。

多级容器        

        然后对于多级容器,还需要一个递归的重载:

inline std::string SeqToStr(const Iterable& arr) {return SeqToStr(arr, [](auto&& ss, auto&& arr) -> decltype(auto) {return ss << SeqToStr(arr);});
}

        最后就是需要区分一级和多级容器这两种情况。

自动区分级别

C++14实现

        对于C++14,只能用SFINAE特性了,要知道容器里元素的类型,以及元素类型是否可直接打印。获得容器的元素类型,只需要获得std::begin(arr)的返回值类型即可,这样写避免某些自定义的容器不支持默认构造,或者没有begin()成员函数。

template <typename T>
struct ValueType {using type = std::decay_t<decltype(*std::begin(*static_cast<T*>(nullptr)))>;
};
template <typename T, std::size_t Size>
struct ValueType<T[Size]> {using type = T;
};
template <typename T>
using value_type_t = typename ValueType<T>::type;

        然后就是判断元素是否可以打印,这里以是否能被cout<<接收为标准,同时,考虑到原生数组可以以指针的形式被打印,所以判断的时候,需要排除这种情况:

template <typename T>
class Printable {template <typename U>static std::true_type test(decltype(std::cout << U{}, int{})*);template <typename U>static std::false_type test(...);public:static constexpr bool value =!std::is_array<T>::value &&std::is_same<decltype(test<T>(nullptr)), std::true_type>::value;
};

        最终,上面一级和多级的重载,可以加上条件模板了:

// print an iterable struct(vector<int>, set<int>, int[3], array<int,3>, etc)
template <typename Iterable,std::enable_if_t<Printable<value_type_t<Iterable>>::value, int> = 0>
std::string SeqToStr(const Iterable& arr) {return SeqToStr(arr, [](auto& ss, auto&& ele) -> decltype(auto) { return ss << ele; });
}
// print an multi-dimensional struct(int[3][3], set<vector<set<int>>>, etc)
template <typename Iterable,std::enable_if_t<!Printable<value_type_t<Iterable>>::value, int> = 0>
std::string SeqToStr(const Iterable& arr) {return SeqToStr(arr, [](auto&& ss, auto&& arr) -> decltype(auto) {return ss << SeqToStr(arr);});
}

C++20实现

        对于C++20,可以用concept来代替上面的Printable、一级和多级容器的重载,大意一样,但更为简洁:

template <typename Iterable>
std::string SeqToStr(const Iterable& arr) {using ele_type = value_type_t<Iterable>;if constexpr (requires{std::cout << ele_type{}; } && !std::is_array_v<ele_type>) {return SeqToStr(arr, [](auto& ss, auto&& ele) -> decltype(auto) { return ss << ele; });} else {return SeqToStr(arr, [](auto&& ss, auto&& arr) -> decltype(auto) {return ss << SeqToStr(arr);});}}

测试代码

#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <list>
#include <set>
#include <unordered_map>
#include <array>int main() {using std::cout, std::endl;std::initializer_list<int> list{1, 2, 3, 4, 5};int arr[][2]{{1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 6}};std::vector<int> vec{2, 4, 6, 8, 0};std::array<std::vector<int>, 2> arr_vec{std::vector<int>{1, 2, 3, 4, 5},std::vector<int>{11, 22, 33, 44, 55}};std::set<int> set{1, 3, 5, 7};std::unordered_map<int, char> umap{{1, 'a'}, {2, 'b'}, {3, 'c'}};cout << SeqToStr(std::initializer_list{1, 2, 3, 4, 6}) << endl;cout << SeqToStr(list) << endl;cout << SeqToStr(arr) << endl;cout << SeqToStr(vec) << endl;cout << SeqToStr(arr_vec) << endl;cout << SeqToStr(set) << endl;cout << SeqToStr(umap, [](auto&& ss, auto&& ele) -> decltype(auto) {return ss << "{key=" << ele.first << ",value=" << ele.second << '}';}) << endl;
}

   期望输出为    

[1,2,3,4,6]
[1,2,3,4,5]
[[1,2],[2,3],[3,4],[4,5],[5,6]]
[2,4,6,8,0]
[[1,2,3,4,5],[11,22,33,44,55]]
[1,3,5,7]
[{key=1,value=a},{key=2,value=b},{key=3,value=c}]

、如果包含了下面这篇文档对bitset遍历的实现,用基于范围的for循环遍历bitset的所有有效位置_bitset 遍历-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/sinat_39088557/article/details/116431911        还可以这么用:

#include <bitset>
int main() {using std::cout, std::endl;std::bitset<65537> bs{ 0xc };bs.set(63);bs.set(64);bs.set(65);bs.set(264);bs.set(364);bs.set(664);bs.set(6663);bs.set(64645);bs.set(65536);cout << SeqToStr(BitsetRange(std::bitset<65537>(0xfabcd0))) << endl;cout << SeqToStr(BitsetRange(bs)) << endl;auto bs1 = bs;bs1.set(7);bs1.set(63, false);cout << SeqToStr(std::vector{BitsetRange(bs), BitsetRange(bs1)});}

期望输出为:

[4,6,7,10,11,12,13,15,17,19,20,21,22,23]
[2,3,63,64,65,264,364,664,6663,64645,65536]
[[2,3,63,64,65,264,364,664,6663,64645,65536],[2,3,7,64,65,264,364,664,6663,64645,65536]]

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

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

相关文章

线上民族传统服饰商城

摘 要 随着互联网的不断发展和普及&#xff0c;电子商务成为了人们生活中不可或缺的一部分。传统的线下购物方式逐渐被线上购物所取代&#xff0c;人们越来越习惯在互联网上购物。而民族传统服饰作为我国丰富多样的民族文化的重要组成部分&#xff0c;具有独特的艺术价值和商业…

unity VR Interaction Framework 创建新手势

提示&#xff1a;文章有错误的地方&#xff0c;还望诸位大神不吝指教&#xff01; 文章目录 前言一、新建物体&#xff0c;并添加必要组件二、添加抓取点三、查看手势的可视化样式四、制作新的手势1.点击编辑2.根据需求调节手指关节3.保存手势4. 使用创建的手势5.运行 总结 前言…

远程过程调用协议gRPC及在go环境下的使用

1. 远程过程调用协议 1.1 定义 远程过程调用(Remote Procedure Call&#xff0c;PRC是一种进程间通信技术&#xff0c;它使得程序可以像调用本地函数一样调用远程服务器上的函数。RPC 屏蔽了底层的通信细节&#xff0c;让开发者能够更专注于业务逻辑&#xff0c;而无需关心网络…

无源电压继电器 JDY-1210AW 导轨安装 约瑟JOSEF

系列型号&#xff1a; JDY-1002AW电压继电器&#xff1b;JDY-1002B电压继电器&#xff1b; JDY-1110AW电压继电器&#xff1b;JDY-1110B电压继电器&#xff1b; JDY-1220AW电压继电器&#xff1b;JDY-1220B电压继电器&#xff1b; JDY-1100AW电压继电器&#xff1b;JDY-110…

服务器数据恢复—用raid6阵列磁盘组建raid5阵列如何恢复原raid数据?

服务器存储数据恢复环境&#xff1a; 华为OceanStor 5800存储&#xff0c;该存储中有一组由10块硬盘组建的raid6磁盘阵列&#xff0c;供企业内部使用&#xff0c;服务器安装linux操作系统EXT3文件系统&#xff0c;划分2个lun。 服务器存储故障&#xff1a; 管理员发现存储中rai…

JavaScript的学习之dom的查询(一)

一、获得元素 通过document对象调用&#xff1a; getElementById()&#xff1a;通过id属性获取一个元素节点对象getElementsByTagName()&#xff1a;通过标签名获取一组元素节点对象getElementsByName()&#xff1a;通过name属性来获取一组元素节点对象 核心学习代码 <scrip…

记录一次即将出现的钓鱼新方式

钓鱼通常是内网渗透过程中的最为常见的入口方式&#xff0c;但是随着蓝队人员溯源反制思路开阔&#xff0c;入侵排查能力提升&#xff0c;钓鱼也越来越困难&#xff0c;这里就记一种不同寻常的钓鱼方式。 pip install 的执行流程&#xff1a; 先获取到远端的服务器地址 url 比…

单目标应用:基于吸血水蛭优化器(Blood-Sucking Leech Optimizer,BSLO)的微电网优化(MATLAB代码)

一、微电网模型介绍 微电网多目标优化调度模型简介_vmgpqv-CSDN博客 参考文献&#xff1a; [1]李兴莘,张靖,何宇,等.基于改进粒子群算法的微电网多目标优化调度[J].电力科学与工程, 2021, 37(3):7 二、吸血水蛭优化器求解微电网 2.1算法简介 吸血水蛭优化器&#xff08;B…

【Java Web】Tomcat服务器

目录 一、Tomcat是什么 二、Tomcat安装 三、Tomcat相关目录 四、Web项目标准目录结构规范 五、Tomcat项目部署方式 六、IDEA关联本地Tomcat 七、HTTP协议 7.1 http的交互方式 7.1.1 http长连接和短连接 7.1.2 http1.1缓存机制 7.2 http数据报文格式 八、常见响应状态码 一、Tom…

印刷企业数字工厂管理系统如何保障产品质量

一、引言 随着信息技术的迅猛发展&#xff0c;印刷行业也迎来了数字化转型的浪潮。数字工厂管理系统作为这一转型的核心工具&#xff0c;不仅在提高生产效率、优化资源配置方面发挥了重要作用&#xff0c;更在保障产品质量上扮演着关键角色。本文将深入探讨印刷企业数字工厂管…

浏览器扩展V3开发系列之 chrome.contextMenus 右键菜单的用法和案例

【作者主页】&#xff1a;小鱼神1024 【擅长领域】&#xff1a;JS逆向、小程序逆向、AST还原、验证码突防、Python开发、浏览器插件开发、React前端开发、NestJS后端开发等等 chrome.contextMenus 允许开发者向浏览器的右键菜单添加自定义项。 在使用 chrome.contextMenus 之前…

本地读取classNames txt文件

通过本地读取classNames,来减少程序修改代码,提高了程序的拓展性和自定义化。 步骤: 1、输入本地路径,分割字符串。 2、将className按顺序放入vector容器中。 3、将vector赋值给classNmaes;获取classNames.size(),赋值给CLASSES;这样,类别个数和类别都已经赋值完成。…

Python | Leetcode Python题解之第199题二叉树的右视图

题目&#xff1a; 题解&#xff1a; class Solution:def rightSideView(self, root: TreeNode) -> List[int]:rightmost_value_at_depth dict() # 深度为索引&#xff0c;存放节点的值max_depth -1stack [(root, 0)]while stack:node, depth stack.pop()if node is not…

第N8周:seq2seq翻译实战-Pytorch复现

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 一、前期准备 from __future__ import unicode_literals, print_function, division from io import open import unicodedata import s…

50、基于NARX神经网络的磁悬浮建模(matlab)

1、NARX神经网络简介 NARX&#xff08;非线性自回归外部输入&#xff09;神经网络是一种用于非线性建模和预测的神经网络结构。与传统的自回归模型不同&#xff0c;NARX网络可以接收外部输入来影响输出结果&#xff0c;从而更好地捕捉系统的复杂性和非线性特征。 NARX神经网络…

竞赛选题 python+深度学习+opencv实现植物识别算法系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的植物识别算法研究与实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;4分工作量&#xff1a;4分创新点&#xff1a;4分 &#x1f9ff; 更多…

基于Java微信小程序自驾游拼团设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…

27. 高级特性(下)

目录 一、为了类型安全和抽象而使用 newtype 模式二、使用类型别名创建类型同义词2.1 使用type关键赋予现有类型一个别名2.2 减少重复2.3 与Result<T, E>结合使用2.4 从不返回的 never type 三、高级函数和闭包3.1 函数指针3.2 返回闭包 四、宏4.1 宏和函数的区别4.2 mac…

python基础语法 003-3 数据类型元组

1 元组 1.1 元组含义 1.1.1 元组的表示 #元组的表示方法:() names ("xiaoyun", "xiaoming") print(names)--结果------- (xiaoyun, xiaoming) 1.1.2 空元组 #空元组 names () print(type(names)) print(len(names))----------------结果--------- &l…

安装vue开发者工具

浏览器控制台提示&#xff1a; 打开网址 GitHub - vuejs/devtools: ⚙️ Browser devtools extension for debugging Vue.js applications. 点击添加 上图地址&#xff1a;Installation | Vue Devtools 安装好了