news 2026/11/2 6:09:11

C/C++自定义std::format格式化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C/C++自定义std::format格式化
C++
#include <string> #include <sstream> #include <algorithm> #include <iostream> #include <iomanip> template <class T0, class T1, class = void> struct _has_stream_bit_shl : std::false_type {}; template <class T0, class T1> struct _has_stream_bit_shl<T0, T1, std::void_t<decltype( std::declval<T0>() << std::declval<T1>() )>> : std::true_type {}; template <class T, class = void> struct _has_range_begin_end : std::false_type {}; template <class T> struct _has_range_begin_end<T, std::void_t<decltype( std::begin(std::declval<T>()) != std::end(std::declval<T>()) )>> : std::true_type {}; template <class T, class = void> struct _has_tuple_size : std::false_type {}; template <class T> struct _has_tuple_size<T, std::void_t<decltype( std::tuple_size<T>::value )>> : std::true_type {}; struct _to_stream_impl { template <class Os, class T, std::size_t ...Is> static void _helper_tuple_to_stream(Os& os, T const& t, std::string_view fms, std::index_sequence<Is...>) { os << '('; (to_stream(os, std::get<0>(t), fms), ..., (os << ' ', to_stream(os, std::get<Is + 1>(t), fms))); os << ')'; } template <class Os, class T, std::enable_if_t<!_has_stream_bit_shl<Os&, T const&>::value && (std::tuple_size<T>::value >= 1), int> = 0> static void to_stream(Os& os, T const& t, std::string_view fms) { return _helper_tuple_to_stream(os, t, fms, std::make_index_sequence<std::tuple_size_v<T> -1>{}); } template <class Os, class T> static auto to_stream(Os& os, T const& t, std::string_view fms) -> decltype((std::enable_if_t<!_has_stream_bit_shl<Os&, T const&>::value && !_has_range_begin_end<T>::value, void>)(std::declval<T&>()[0], std::declval<T&>().length())) { os << "[glm: "; for (int i = 0; i < t.length(); ++i) { to_stream(os, t[i], fms); os << ", "; } os << "]"; } template <class Os, class T, std::enable_if_t<!_has_stream_bit_shl<Os&, T const&>::value && (std::tuple_size<T>::value == 0), int> = 0> static void to_stream(Os& os, T const& t, std::string_view fms) { os << "()"; } template <class Os, class T, std::enable_if_t<!_has_stream_bit_shl<Os&, T const&>::value && !_has_tuple_size<T>::value&& _has_range_begin_end<T>::value, int> = 0> static void to_stream(Os& os, T const& t, std::string_view fms) { auto it = std::begin(t); auto eit = std::end(t); os << '['; if (it != eit) { to_stream(os, *it, fms); ++it; for (; it != eit; ++it) { os << ' '; to_stream(os, *it, fms); } } os << ']'; } template <class Os, class T, std::enable_if_t<_has_stream_bit_shl<Os&, T const&>::value && !std::is_enum<T>::value, int> = 0> static void to_stream(Os& os, T const& t, std::string_view fms) { auto flgs = os.flags(); if (fms.size() != 0) { if (fms.size() != 0 && fms[0] == '-') { fms = fms.substr(1); os << std::right; } if (fms.size() != 0 && fms[0] == '0') { fms = fms.substr(1); os << std::setfill('0'); } { int tmp = 0; while (fms.size() != 0 && '0' <= fms[0] && '9' >= fms[0]) { tmp *= 10; tmp += fms[0] - '0'; fms = fms.substr(1); } if (tmp != 0) os << std::setw(tmp); } if (fms.size() != 0 && fms[0] == '.') { fms = fms.substr(1); int tmp = 0; while (fms.size() != 0 && '0' <= fms[0] && '9' >= fms[0]) { tmp *= 10; tmp += fms[0] - '0'; fms = fms.substr(1); } os << std::setprecision(tmp); } if (fms.size() != 0) { switch (fms[0]) { case 'x': os << std::hex; break; case 'd': os << std::dec; break; case 'o': os << std::oct; break; }; } } os << t; os.flags(flgs); } template <class Os, class T, std::enable_if_t<std::is_enum<T>::value && _has_stream_bit_shl<Os&, typename std::underlying_type<T>::type const&>::value, int> = 0> static void to_stream(Os& os, T const& t, std::string_view fms) { os << std::underlying_type_t<T>{t}; } }; template <class Os, class T> void to_stream(Os& os, T const& t, std::string_view fms) { _to_stream_impl::to_stream(os, t, fms); } template <class T> std::string to_string(T const& t, std::string_view fms) { std::ostringstream ss; to_stream(ss, t, fms); return ss.str(); } template <class T> std::string to_string(T const& t) { if constexpr (std::is_convertible_v<T, std::string>) { return t; } else { std::ostringstream ss; to_stream(ss, t, {}); return ss.str(); } } template <int curr, class Os, class It, class ...Args> bool __format(Os& os, It fb, It fe, std::tuple<Args const &...> const& args) { if constexpr (curr >= sizeof...(Args)) { if (fb != fe) os << std::string_view(fb, fe - fb); return curr > sizeof...(Args); } else { if (fb == fe) return false; auto ib = std::find(fb, fe, '{'); if (ib == fe) return false; os << std::string_view(fb, ib - fb); ++ib; auto ie = std::find(ib, fe, '}'); if (ie == fe) return false; ++ie; auto fms = std::string_view(ib, ie - ib); if (auto i = fms.find(':'); i != std::string_view::npos) { fms = fms.substr(i + 1); } to_stream(os, std::get<curr>(args), fms); return __format<curr + 1>(os, ie, fe, args); } } template <class Os, class ...Args> bool format_to(Os& os, std::string_view fmt, Args const &...args) { return __format<0>(os, fmt.data(), fmt.data() + fmt.size(), std::tuple<Args const &...>(args...)); } template <class ...Args> std::string format(std::string_view fmt, Args const &...args) { std::stringstream ss; format_to(ss, fmt, args...); return ss.str(); } void test() { std::cout << format("add({}+{})={}\n", 1, 2, 3); }
C
#include <cstdio> #include <cstring> #include <cstdlib> #include <stdarg.h> #include <string> template <class ...Ts> std::string cformat(const char *fmt, Ts &&...ts) { int n = snprintf(nullptr, 0, fmt, std::forward<Ts>(ts)...); if (n < 0) return {}; std::string res; res.resize(n + 2); n = snprintf(res.data(), n + 1, fmt, std::forward<Ts>(ts)...); res.resize(n); return res; }

输出: add(1+2)=3


创作不易,小小的支持一下吧!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/2 6:09:09

C++旋转点坐标计算

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/2 6:09:06

C++ ariac2 Windows库编译

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/2 6:09:03

Linux C编译器从零开发一

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/2 6:07:50

脉冲线性调频雷达信号处理全链路解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/2 6:07:36

基于FPGA与STM32的PLFM_RADAR脉冲压缩雷达系统设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/2 6:07:06

工业SPI隔离通信设计:MAX14431BAEE+与PIC18F4458实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华