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

        在日志打印中,往往有打印一个数组、集合等容器中的每个元素的需求,这些容器甚至可能嵌套起来,如果每个地方都用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.运行 总结 前言…

等保测评——安全通信网络——安全区域边界

安全通信网络 网络架构 a) 应保证网络设备的业务处理能力满足业务高峰期需要&#xff1b; b) 应保证网络各个部分的带宽满足业务高峰期需要&#xff1b; c) 应划分不同的网络区域&#xff0c;并按照方便管理和控制的原则为各网络区域分配地址&#xff1b; 应核查是否依据重…

远程过程调用协议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 比…

node.js 面试题 1

### 明天要去面试了 今天晚上突击一下node.js 什么是Node.js&#xff1f;它有什么特点&#xff1f; Node.js是一个基于Chrome V8引擎的JavaScript运行环境&#xff0c;它允许在服务器端运行JavaScript代码。它的特点包括单线程、非阻塞I/O、事件驱动等 …

dispatch_after

dispatch_after dispatch_after dispatch_after dispatch_after函数并不是延迟对应时间后立即执行block块中的操作&#xff0c;而是将任务追加到对应队列中&#xff0c;考虑到队列阻塞等情况&#xff0c;所以这个任务从加入队列到真正执行的时间是不准确的。 dispatch_after(…

Kubernetes CSI livenessprobe探活

Kubernetes CSI livenessprobe探活 要实现一个Kubernetes CSI的livenessprobe探活&#xff0c;可以有以下三种方法&#xff1a; HttpServer 1、在CSI中实现一个简单的HttpServer&#xff0c;暴露探活接口&#xff1b; GRPC探测 2、CSI镜像中&#xff0c;增加grpcurl命令&a…

单目标应用:基于吸血水蛭优化器(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…

什么是堡垒机(运维审计系统)?

一、堡垒机是什么 1.1 堡垒机的来由 堡垒机是从跳板机&#xff08;也叫前置机&#xff09;的概念演变过来的。早在2000年左右的时候&#xff0c;一些中大型企业为了能对运维人员的远程登录进行集中管理&#xff0c;会在机房部署一台跳板机。 跳板机其实就是一台lunix/windows…

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

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