跳转至内容
  • A place to talk about whatever you want

    24 主题
    165 帖子
    semmyenatorS

    AREEM,一種無需黑箱的高精度π計算方法
    https://deepwiki.com/semmyenator/AREEM
    這個項目只是一個人完成的小型數學項目,並非一項發明或特殊功能設計。
    希望它對需要旋轉控制的工程師有所幫助。

  • 7 主题
    20 帖子
    SPeakS

    @dustchens 链表结构损坏, 不闭环了 (如果问题解决可以把帖子状态设置为已解决

  • 开源软件 | 开源社区 | 开源理念 | 开源与商业 | 开源可持续发展 等相关话的交流讨论
    注: 这里的"开源"是泛化的共建共享概念, 范围包含 OSI的范围、自由软件、CC等相关内容

    57 主题
    246 帖子
    MoYingJiM

    补一个 0BSD,这个许可证很多时候也被放在与 Unlicense 和 WTFPL 相提并论的(都是公共领域)

  • 56 主题
    249 帖子
    johanvxJ

    johanpoisson#outlook.com

  • 21 主题
    57 帖子
    DoomjustinD
    优雅与效率并存:基于 C++20 Concepts 构建非侵入式 std::format 扩展 1. 背景与痛点:std::format 很好,但还能更好

    在 C++20 引入 std::format 之前,我一直使用 fmt::format 作为格式化输出的首选。两者的 API 几乎一致,但在将其作为标准库迁移并在大型工程落地时,几个显著的痛点让人如鲠在喉:

    满天飞的样板代码:fmt 提供了极为便利的 format_as 机制,而现阶段的 std::format 官方仅支持通过特化 std::formatter<T> 来实现自定义输出。这意味着每次接入一个自定义类型,都必须硬着头皮手写一遍冗长且高度重复的模板样板代码,心智负担极重。 手动调用的累赘感:为了逃避上述的样板代码,很多人会退而求其次,在类内提供一个 to_string() 方法。但代价是每次打印都必须显式调用(如 std::println("{}", obj.to_string())),不仅破坏了格式化字符串原有的简洁语义,写起来也极其繁琐累赘。 类型输出碎片化:如果没有统一约束,工程里的输出方式就会群魔乱舞:有的依赖遗留的 operator<<,有的每次现场手写 std::format("...") 拼接内部字段,代码风格极其割裂。 日志可读性劣化:尤其是枚举类型(enum),默认直接输出底层整数值。在排查问题时面对满屏的“魔术数字”,必须反复去头文件反查定义,十分痛苦。 新类型接入成本高:由于缺乏统一、低成本的扩展范式,每次新增类型都要纠结“这次该怎么格式化”,稍有不慎还会与旧代码的重载产生隐式冲突。 2. 核心设计目标

    为了彻底解决上述问题,我构建了一个轻量级的扩展组件,旨在实现以下目标:

    复刻体验:提供类似 fmt::format_as 极低成本的自定义接入点,告别特化样板代码。 鸭子类型:引入 Pythonic 的约定,支持自动探测并调用类内的 to_string() 或 to_repr()。 原生枚举:借助 magic_enum,实现枚举值的直接名称输出(告别魔术数字)。 无痛兼容:对已实现 operator<< 的遗留类型提供平滑过渡。 非侵入式:不修改标准库,不污染业务代码,只需 import 即可生效。 3. 优先级路由与核心用法速览

    为了避免不同格式化方式之间的冲突,本组件在编译期规定了严格的优先级路由。以下是 5 种分类的详细用法:

    优先级 接口约定 适用场景与说明 1 format_as(v) 最佳实践。继承底层类型的格式规范。 2 v.to_string() 常规业务输出。返回 std::string。 3 v.to_repr() 调试/诊断输出。返回结构化语义表示。 4 enum / enum class 自动转换为只读的枚举名字符串。 5 operator<<(ostream) 兜底方案。捕获传统流输出。 3.1 方式一:基于 format_as 的无缝转发(⭐️ 推荐)

    特性:返回整数或其他基础类型时,格式规范(如 {:#x}/{:08d} 等)将被完整透传

    struct Flags { int bits; }; // 自由函数,通过 ADL 查找 auto format_as(const Flags& f) { return f.bits; } std::println("{:#010x}", Flags{255}); // 输出: 0x000000ff 3.2 方式二:基于 to_string 的常规输出

    特性:不再需要手动加 .to_string(),组件会自动探测并调用。适用于需要将对象状态转化为人类可读字符串的常规业务场景。

    struct Version { int major, minor; auto to_string() const -> std::string { return std::format("{}.{}", major, minor); } }; std::println("{}", Version{1, 2}); // 输出: 1.2 3.3 方式三:基于 to_repr 的诊断输出

    特性:语义上专用于 Debug 打印,输出包含类型元数据的结构化信息。

    struct Node { int id; auto to_repr() const -> std::string { return std::format("Node(id={})", id); } }; std::println("{}", Node{42}); // 输出: Node(id=42) 3.4 方式四:枚举类型的自动反射

    特性:彻底告别输出枚举整数值的痛苦,自动打印枚举项名称。

    enum class ScopedState { idle, running }; std::println("{}", ScopedState::running); // 输出: running 3.5 方式五:兼容遗留 operator<<

    特性:作为最后的兜底方案,让老旧代码无需任何改动即可接入 std::format 体系。

    struct Legacy { int value; friend auto operator<<(std::ostream& os, const Legacy& v) -> std::ostream& { return os << "legacy:" << v.value; } }; std::println("{}", Legacy{7}); // 输出: legacy:7 4. 揭秘底层机制:编译期分派

    本组件的核心魔法在于编译期 SFINAE 的现代化平替——C++20 Concepts

    首先,定义一组 Concept 来嗅探类型的能力:

    import std; template<typename T> concept has_format_as = requires(const T& t) { format_as(t); }; template<typename T> concept has_to_string = requires(const T& t) { t.to_string(); }; template<typename T> concept has_to_repr = requires(const T& t) { t.to_repr(); }; template<typename T> concept has_ostream = requires (const T& t, std::ostream& os) { os << t; };

    接着,利用约束对 std::formatter<T> 进行特化,实现按优先级的路由。以 to_string 为例:

    // 优先级 2:拦截具有 to_string 的类型 template <typename T> requires (!xin::has_format_as<T>) && xin::has_to_string<T> struct std::formatter<T>: std::formatter<std::string> { auto format(const T& value, std::format_context& ctx) const { return std::formatter<std::string>::format(value.to_string(), ctx); } };

    ⚠️ 细节预警:在处理 operator<< 兜底时,为了避免与标准库自带特化的类型(如 std::string)发生重定义冲突,必须增加一个用户自定义类型(User-Defined Types)的拦截器:

    template<typename T> concept user_defined_type = std::is_class_v<std::remove_cvref_t<T>> || std::is_union_v<std::remove_cvref_t<T>> || std::is_enum_v<std::remove_cvref_t<T>>; // 优先级 5:兜底 operator<< template<typename T> requires (!xin::has_format_as<T>) && (!xin::has_to_string<T>) && (!xin::has_to_repr<T>) && xin::user_defined_type<T> // 核心拦截器 && xin::has_ostream<T> struct std::formatter<T>: std::formatter<std::string> { auto format(const T& value, std::format_context& ctx) const { std::ostringstream os; os << value; return std::formatter<std::string>::format(os.str(), ctx); } }; 5. 性能考量 (Zero-Cost Abstraction)

    由于分派机制完全建立在 C++20 Concepts 上,这层抽象在运行期是零成本(Zero-Cost)的。最终的性能仅取决于你选择的实现路径:

    极致性能:使用 format_as 转发给基础类型,与原生 std::format 无异。 中等开销:使用 to_string / to_repr,存在 std::string 构造时的动态内存分配。 最高损耗:使用 operator<<,涉及 std::ostringstream 的构造与格式化,建议仅作为过渡方案。 6. 遗憾与未来展望

    目前的一个小缺憾在于,受限于 std::format 解析上下文的复杂性,我们无法像 Python 那样通过语法糖(如 {user!r})动态强制走 __repr__ 路径。目前 to_string 和 to_repr 仍是一种严格的回退关系。期待未来标准库开放更灵活的扩展能力。

    🔗 完整资源指路:

    源码实现:src/common/format.cppm 详细文档:docs/common/format.md

    只需在项目中 import xin.format;,即可享受这一切。

  • 一个技术知识分享、学习、交流的社区

    15 主题
    50 帖子
    sunrisepeakS

    @Doomjustin 版块已创建, 可以检查确认一下是否有话题贴/Topic工具的权限

    https://forum.d2learn.org/category/26/xin
  • Got a question? Ask away!

    4 主题
    14 帖子
    SPeakS

    备注一下使数学公式的使用语法

    单行公式语法 - $ 你的公式 $

    $ log_2^n $

    $ log_2^n $

    多行公式语法 - $$ 你的公式 $$

    $$ log_2^n => log_2^9 = 3 , n = 9 $$

    $$
    log_2^n =>
    log_2^9 = 3, n = 9
    $$

公告栏 | Bulletin Board

欢迎加入d2learn社区 - 社区指南
Welcome to the d2learn Community - Community Guide

一个以 [知识、技术、代码、项目、想法、开源] 相关话题为主导的社区
A community focused on topics related to [knowledge, technology, code, projects, ideas, and open source].


在线用户