首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

可以在没有宏的情况下在C++20中实现一次log吗?

在C++20中,即使没有宏(macro),也可以通过内联函数和模板来实现日志记录功能。以下是一个简单的示例,展示了如何在不使用宏的情况下实现一次性的日志记录:

基础概念

  • 内联函数:编译器会在调用点直接展开函数体,减少函数调用的开销。
  • 模板:允许编写与类型无关的代码,提高代码的复用性。
  • RAII(Resource Acquisition Is Initialization):一种管理资源的惯用法,确保资源在对象生命周期结束时被正确释放。

示例代码

代码语言:txt
复制
#include <iostream>
#include <string_view>
#include <utility>

// 定义一个简单的日志级别枚举
enum class LogLevel {
    Info,
    Warning,
    Error
};

// 内联函数,用于输出日志
inline void log(LogLevel level, std::string_view message) {
    switch (level) {
        case LogLevel::Info:
            std::cout << "[INFO] ";
            break;
        case LogLevel::Warning:
            std::cout << "[WARNING] ";
            break;
        case LogLevel::Error:
            std::cout << "[ERROR] ";
            break;
    }
    std::cout << message << std::endl;
}

// 模板函数,用于简化日志记录
template<typename... Args>
inline void log_once(LogLevel level, const char* format, Args&&... args) {
    log(level, fmt::format(format, std::forward<Args>(args)...));
}

int main() {
    // 使用log_once函数记录日志
    log_once(LogLevel::Info, "This is an info message with number: {}", 42);
    log_once(LogLevel::Warning, "A warning occurred!");
    log_once(LogLevel::Error, "An error happened: {}", "File not found");

    return 0;
}

优势

  1. 类型安全:使用模板和内联函数可以避免宏带来的类型不安全问题。
  2. 可读性:代码更易读,调试更方便。
  3. 灵活性:可以轻松扩展日志级别和格式化选项。

类型

  • 内联函数:直接在调用点展开,减少函数调用开销。
  • 模板函数:提供类型安全的泛型编程能力。

应用场景

  • 调试信息:在开发和调试阶段记录关键信息。
  • 运行时监控:在生产环境中记录系统状态和异常情况。
  • 日志分析:收集和分析日志数据以优化系统性能。

可能遇到的问题及解决方法

  1. 性能问题:如果日志记录频繁且量大,可能会影响性能。可以通过异步日志记录或批量处理来优化。
  2. 线程安全:多线程环境下需要确保日志记录的线程安全性。可以使用线程安全的日志库或手动加锁。
  3. 格式化问题:复杂的格式化需求可以通过引入第三方库(如fmt库)来解决。

通过上述方法,可以在C++20中实现高效且类型安全的日志记录功能,而无需依赖宏。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

我可以在不source脚本的情况下将变量从Bash脚本导出到环境中吗

echo $VAR 有没有一种方法可以通过只执行 export.bash 而不 source 它获取 $VAR? 答: 不可以。 但是有几种可能的解决办法。...在调用 shell 的上下文中执行脚本: $ cat set-vars1.sh export FOO=BAR $ . set-vars1.sh $ echo $FOO BAR 另一种方法是在脚本中打印设置环境变量的命令.../set-vars2.sh)" $ echo "$FOO" BAR 在终端上执行 help export 可以查看 Bash 内置命令 export 的帮助文档: # help export export...-f 指 shell 函数 -n 从每个(变量)名称中删除 export 属性 -p 显示所有导出变量和函数的列表 ---- 参考: stackoverflow question 16618071...help eval 相关阅读: 用和不用export定义变量的区别 在shell编程中$(cmd) 和 `cmd` 之间有什么区别 ----

18020

如何在C++17中实现stackless coroutine以及相关的任务调度器

前言 C++协程一直是大家比较关注的一个技术点, 在C++20 coroutine属性正式推出之前, 就已经有很多项目实装了, 实现机制也略也差异, 下面先来简单看下比较常见的实现方式: 1.1 基于...对于无GC的情况, 也有部分项目使用这种模式来实现自己的协程, 但对比stackful的协程使用上会稍显麻烦, 原来可以正常使用的stack变量需要手动处理, 存储在特定的地方. 1.3 C++20的coroutine.... 3. stackless coroutine实现 当前框架的无栈协程实现是基于switch case的duff device特性来实现的, 通过对应的case label, 可以在重入一个函数的时候跳转到不同的...对于一段代码, 整个协程化的机制大致如下: 宏展开, 形成switch(coroutine_state()){case 挂起点: }这种结构的代码, 通过关键宏的辅助, 我们可以实现每次resume CoPromise...在具备条件的情况下, 推荐直接使用C++20的coroutine特性, 笔者项目实装对比下来, 整体的业务侧编码舒适度, 以及可控性, 还是高非常多的.

1.9K20
  • C++20新书推荐!

    今天推荐一个新书,C++20的一些特性: 通过Modules淘汰了C++之前编写大程序的陈旧方式; 使用Concepts帮助创建类型安全的模板和实现灵活的模板特化; 使用Ranges彻底改变了处理数据的方式...C++20中可以使用midpoint计算中位数、lerp计算线性差值,std::is_bounded_array检查数组是不是有界,并添加了Ranges库以用来处理元素范围和的组件。...C++20中,可使用lambda表达式捕获this方式,lambda表达式可以使用模板,某些时候不需要使用typename,结构体可以直接初始化。...范围库 使其能够在容器上直接表达算法,通过管道符号组合算法,并将其用于数据流中。范围是概念的首个客户,它支持的算法满足以下条件:可以直接在容器上操作,无需迭代器指定范围;可以宽松地评估;可以组合。...模块能够实现更快的编译时间、宏的隔离、表达代码的逻辑结构、不必再使用头文件,且能够摆脱丑陋的宏方法。 总之,C++20作为一个重大版本发布,又给C++带来了更多新的可能。

    80610

    C++20功能测试宏:搭建语言特性与编译器支持的稳固桥梁

    它们各自有着不同的定义和使用方式,分别用于检测编译器对特定语言特性的支持,以及标准库的实现情况。1. 语言特性宏语言特性宏在每个翻译单元中都会预先定义。...三、功能测试宏的实际应用示例下面通过几个具体的示例,来展示功能测试宏在实际代码中是如何使用的,以及如何通过它们来检测编译器对特定特性的支持情况。...示例3:基于特性支持的条件编译假设我们要编写一个程序,根据编译器对C++20范围库的支持情况,选择不同的实现方式。...开发者无需担心因编译器差异而导致的代码错误,大大提高了代码的复用性和可维护性。灵活性:开发者可以根据编译器对特性的支持情况,灵活地启用或禁用代码中的某些功能。...六、总结C++20功能测试宏的出现,无疑是C++语言发展历程中的一个重要里程碑。它为开发者提供了一种标准化、跨编译器的方式,能够准确检测语言特性的支持情况。

    5410

    「深入浅出」主流前端框架更新批处理方式

    结果是:vue 底层通过批量处理,只让组件 update 一次。 2 一次 react 案例 上面介绍了在 vue 中更新批处理的案例之后,我们来看一下在 react 中的批量更新处理。...批处理主要是出于对性能方面的考虑,这里拿 react 为例子,看一下批处理前后的对比情况: 例子一:假设没有批量更新: / ------ js 层面 ------ 第一步:发生点击事件触发一次宏任务。...我们可以看到如果没有批量更新处理,那么会多走很多步骤,包括 render 阶段 ,commit 阶段,dom 的更新等,这些都会造成性能的浪费,接下来看一下有批量更新的情况。 例子二:存在批量更新。...所谓宏任务,我们可以理解成, 标签中主代码执行,一次用户交互(比如触发了一次点击事件引起的回调函数),定时器 setInterval ,延时器 setTimeout 队列, MessageChannel...本质上外层在 React 事件系统处理函数的上下文中,这样的情况下,就可以通过一个开关,证明当前更新是可控的,可以做批量处理。接下来 React 就用一次就可以了。

    78620

    解读C++即将迎来的重大更新(一):C++20的四大新特性

    C++20 有很多更新,上图展示了 C++20 更新的概况。下面作者首先介绍 了 C++20 的编译器支持情况,然后介绍 The Big Four(四大新特性)以及核心语言方面的新特性。...我们这里不介绍 C++20 的具体协程,而会介绍编写协程的框架。编写协程的框架由 20 多个函数构成,其中一部分需要你去实现,另一部分则可能需要重写。因此,你可以根据需求调整协程。...在 getNext 调用之后,这个协程再一次暂停。其暂停会一直持续到下一次调用 next()。我的这个示例中有一个很大的未知,即 getNext 函数的返回值 Generator。...这部分内容很复杂,后面我在写协程的文章中更详细地介绍。 使用 Wandbox 在线编译器,我可以向你展示这个程序的输出: ? 模块(Module) 模块部分简单介绍一下就好。...模块承诺能够实现: 更快的编译时间; 宏的隔离; 表达代码的逻辑结构; 不必再使用头文件(header file); 摆脱丑陋的宏方法。

    1.6K20

    我用 Rust 改写了自己的C++项目:这两个语言都很折磨人!

    C++ 中多数函数和方法都需要声明两次:一次在 header 里,一次在实现文件里。但 Rust 不需要,因此代码行数会更少。 C++ 的完整构建时间比 Rust 长(Rust 更胜一筹)。...主要影响 Rust 和 C++ 构建时间的问题在于,C++ 的诊断系统是通过大量代码生成、宏、constexpr(常量表达式)实现的,而我在重写 Rust 版时,则用了代码生成、proc 宏、普通宏以及一点点...传闻 proc 宏速度很慢,也有说是因为代码质量太差导致的 proc 宏速度慢。希望我写的 proc 宏还可以(祈祷~)。...我第一次搭建的 Rust 自定义工具链比 Nightly 还要慢 2%,我在 Rust config.toml 的各种选项中反复调整,不断交叉检查 Rust 的 CI 构建脚本以及我自己的脚本,最终在好几天的挣扎后才让这二者性能持平...我不爽吗?确实。在改写过程中,我不断学习着 Rust 相关的知识,比如 proc marco 能替代三个不同代码生成器,简化构建流水线,让新开发者们日子更好过。

    1.5K20

    C++20 Text Formattingfmtlib 适配问题小记

    于此同时,我们的构建系统改成了会检测编译环境是否支持 C++20 Text Formatting ,在支持的情况下使用 C++20 Text Formatting ,在不支持的情况下使用 fmtlib...如果没有自定义 formatter ,在 fmtlib 里是能够自动转换成整数类型的输出的,但是(至少是 MSVC)的 C++20 Text Formatting 实现里是不会自动转换的,我翻了一下ISO...这种情况下,同时在 Visual Studio 2019 version 16.10 之前,VS还没有 /std:c++20 选项,所以cmake会把C++标准设为 /std:c++latest 。...-845572895 简单地说就是 MSVC 对一些C++20特性的实现还没有进入ABI稳定期,所以在使用 /std:c++20 时并不会启用 C++20 里的一些内容,包括但不限于Text Formatting...另一方面针对MSVC的这种情况,在构建系统中对 C++20 Text Formatting 的检测脚本做了适配。

    1.3K20

    打通游戏服务端框架的C++20协程改造的最后一环

    在最后的改造过程中,因为C++20协程还是比较新的东西,我们希望在某些开发环境测试新协程,老环境还是走原先的协程调用方式,我设计了一套对RPC和任务系统的抽象,让无论是新协程还是老协程的调用方式都保持一致...这里有感兴趣的同学也可以一起交流下。 task::then() 的生命周期变化 在原先的有栈协程中,我们可以通过 task::then(action) 来串联一些相关逻辑。...而在新式的协程 task_promise 中,为了降低不必要的开销,我没有提供这类事件存储。...那么可能比较自然的能想到,如果我在两个函数里 call_parent() 会调用 call_child() 且返回值一样,某些情况是否可以直接 return call_child() 的返回值,而不使用...整个新协程的实现接入过程中,由于C++20协程能够让我们对类型信息做更多地编译期处理,我也优化了框架层很多类型检测的细节。这些不是C++20协程接入的必须项,这里就不列出了。

    64120

    盘点C++20模块那些事

    3.2 子模块 4.接口与实现 最近看到大佬们写的C++20库使用了module特性,特意来学习一下,于是有了这篇文章,本篇文章的所有代码都在我的星球里面,需要代码的可以扫文末的二维码。...其目的是将模块的接口和实现封装在单个翻译单元中,而不暴露实现细节。 例如:我想要创建一个Shape,计算其面积。...private里面吗,我自己的g++版本是13,目前还不支持,会报如下错误: gcc目前的支持情况,可以戳这里 https://gcc.gnu.org/projects/cxx-status.html...,导入也有一些规则,例如: 不可导入自身 在模块单元中,所有导入必须出现在该模块单元中的任何声明之前。...时,不可以省略主模块名,上面在主分区中引入分区模块,我们可以使用:circle,这里不可以使用.circle。

    46610

    setImmediate() vs setTimeout() 在 JavaScript 中的区别

    Node.js 的异步特性核心是事件循环。 在 Node.js 中,事件循环处理不同的阶段,每个阶段负责执行某些类型的回调。它帮助管理非阻塞任务,确保函数可以异步执行。在这些阶段中,有不同的队列。...即使是 0 毫秒的延迟,它们也要等到下一次循环迭代才能执行。 待处理回调阶段:处理已完成的 I/O 事件,但我们的示例中没有,所以跳过这个阶段。...这意味着 setImmediate() 回调在额外的定时器(如 setTimeout())执行之前被处理,特别是在没有 I/O 的情况下。...现实世界的类比 想象一下在餐馆点餐和饮料。 你点了一道菜(代表 setTimeout(0))。 厨师将其添加到订单队列中,一旦准备好就会送达。...这种情况总是发生吗? 不一定。setImmediate() 和 setTimeout() 的行为可能取决于代码中发生的其他异步操作。

    11810

    万字好文:从无栈协程到C++异步框架!

    聊到中断, 其中比较重要的就是执行环境的保存和恢复了, 而上下文的保存能力可以是操作系统直接提供的, 也可以是程序机制自身所提供的了, 综上所述, 我们大致可以将 c++中的协程的实现方案的迭代看成如下情况...另外, 相关的调度器的实现, 与 C++17 和 C++20 都是兼容的, 像我们项目当时的实现, 是可以很好的做到 C++20 与 C++17 的协程混用的, 也样也方便在过渡阶段, 项目可以更平滑的从...(六)绕开栈变量限制的方法 提到栈变量的限制, 肯定有同学会想到, 是否有方法绕开栈变量的限制, 用一种更灵活的方式处理协程中临时值的存取, 使其在跨越中断点和重入点的情况依然有效? 答案是肯定的....子任务 - 导弹类技能相关代码 对于上面介绍的导弹类技能(火球), 核心实现也比较简单, 实现了一个飞行物按固定速度逼近目标的效果, 具体代码如下, 利用 yield 我们可以实现在飞行物未达到目标点的时候每帧执行一次的效果..., 依赖 C++20 的新特性和我们自己封装的调度器, 我们已经可以很自然很顺畅的用比较低的心智负担来表达原来在 python 中实现的功能了, 这应该算是一个非常明显的进步了。

    1.2K30

    C++20终于要来了…

    在 C++20 中,最重要的两个特性是“模块 (Modules)”和“协程 (Coroutine)”。...“到现在为止,我们有了三种这样的语言特性,让程序员可以(a)将一个用户定义的名称(b)给予某个隐藏自身实现的事物,从而创建自己“语言的力量”。...协程(Coroutine)则表示一个函数的泛化。C++ 的贡献者在协程的提案中解释说:“常规函数总是在起始处开始,然后在结束处退出,而协程还可以中止执行,之后在中断的位置继续执行。”...在一次邮件采访中,C++ 之父 Bjarne Stroustrup 曾表示,“对许多人来说,协程是个新事物。为了从中受益,必须学习一种全新的风格。...在采访中,我们谈到了与 C++20 有关的几个问题。 ? 他说,“我现在很有信心,C++20 会非常出色。我经常提到,C++11 用起来就像是一种全新的语言。

    55920

    从无栈协程到C++异步框架

    聊到中断, 其中比较重要的就是执行环境的保存和恢复了, 而上下文的保存能力可以是操作系统直接提供的, 也可以是程序机制自身所提供的了, 综上所述, 我们大致可以将c++中的协程的实现方案的迭代看成如下情况...另外, 相关的调度器的实现, 与C++17和C++20都是兼容的, 像我们项目当时的实现, 是可以很好的做到C++20与C++17的协程混用的, 也样也方便在过渡阶段, 项目可以更平滑的从C++17向C...提到栈变量的限制, 肯定有同学会想到, 是否有方法绕开栈变量的限制, 用一种更灵活的方式处理协程中临时值的存取, 使其在跨越中断点和重入点的情况依然有效?...在有协程调度器存在的情况下, 业务侧对协程的使用感受, 与其他语言如Python中的差异. 7.1 一个Python实现的技能示例 我们以一个原来在python中利用包装的协程调度器实现的技能系统为例..., 依赖C++20的新特性和我们自己封装的调度器, 我们已经可以很自然很顺畅的用比较低的心智负担来表达原来在python中实现的功能了, 这应该算是一个非常明显的进步了。

    41322

    从无栈协程到 C++异步框架

    聊到中断, 其中比较重要的就是执行环境的保存和恢复了, 而上下文的保存能力可以是操作系统直接提供的, 也可以是程序机制自身所提供的了, 综上所述, 我们大致可以将 c++中的协程的实现方案的迭代看成如下情况...另外, 相关的调度器的实现, 与 C++17 和 C++20 都是兼容的, 像我们项目当时的实现, 是可以很好的做到 C++20 与 C++17 的协程混用的, 也样也方便在过渡阶段, 项目可以更平滑的从...提到栈变量的限制, 肯定有同学会想到, 是否有方法绕开栈变量的限制, 用一种更灵活的方式处理协程中临时值的存取, 使其在跨越中断点和重入点的情况依然有效?..., 在有协程调度器存在的情况下, 业务侧对协程的使用感受, 与其他语言如 Python 中的差异. 7.1 一个 Python 实现的技能示例 我们以一个原来在 python 中利用包装的协程调度器实现的技能系统为例..., 依赖 C++20 的新特性和我们自己封装的调度器, 我们已经可以很自然很顺畅的用比较低的心智负担来表达原来在 python 中实现的功能了, 这应该算是一个非常明显的进步了。

    2.6K41

    Linux 内核大转变:是否将迈入现代 C++ 的时代?

    Peter Anvin 在邮件列表中重启了关于 Linux内核C代码转换为C++的讨论,并陈述了自己的观点。说之前先看一下这个话题的历史背景。...我是说,作为内核中大量宏和内联汇编黑客的作者。...真正让我这么说的是,我们最近要求的 gcc 特定扩展的很多东西实际上是在标准 C++ 中相对容易实现,并且在许多情况下,允许在无需全局代码更改的情况下改进基础设施。...在我的选择中,C++14 是具有合理元编程支持的“最低”版本。没有早期版本的类型地狱(C++11 拥有大部分,但 C++14 填补了一些关键的缺失部分)。...然而,在我看来,C++20 确实是主要的游戏规则改变者;尽管早期版本可以玩很多 SFINAE hacks,但它们也给出了绝对无用的信息作为错误消息。

    33710

    C++20 模块

    长文,预计阅读11分钟,建议收藏 在传统的 C++ 中,使用#include包含头文件进行模块化编程。...但是#include是在预处理阶段引入文件里的内容,尤其是涉及到递归引入时,增加编译时长;头文件做出修改,所有引入该头文件的翻译单元均需要重新编译,也会增加编译时间;同时头文件内的宏、全局变量否是在全局命名空间中定义...模块可以减少这种重复性工作,因为它们会被编译器预先编译一次,并在需要时直接导入。 更清晰的依赖管理:传统的头文件包含方式容易导致头文件的依赖关系混乱,难以维护。...避免宏污染:传统的#include预处理指令可能会引入不必要的宏定义,可能导致命名空间污染和意外的行为。使用模块可以减少这种情况的发生,因为模块的导入更为明确。...进阶 接口和实现分离 通常开发者会将接口的定义和实现书写于头文件和源文件中,模块也可以将模块定义和模块实现分离。一种方式是使用如上的private,在私有片段模块书写模块的实现。

    12310

    曾遭 Linus 炮轰“很烂”的 C++,现受开发者支持:Linux 内核应从 C 转到 C++!

    Peter Anvin 说道,“让我有此感觉的真正原因是,Linux 最近提出的许多针对 GCC 扩展的要求,其实在标准 C++ 中很容易实现,而且在许多情况下,无需修改全局代码即可改进基础架构。”...Peter Anvin 透露,其在 Linux 内核中进行了大量的元编程,这些代码通常使用一些极其糟糕的宏定义来实现,而且几乎无法调试。例如 uaccess.h 中的类型欺骗,其中一些是 H....64 位内核中 32 位用户空间类型的情况,并强制执行字节序转换。...Peter Anvin 也在帖子中特别指出,没有一个正常人会期望使用 C++ 的所有功能。...如果 OOP、异常或 RTTI 在内核中没有意义的话,Linux 就不需要使用它们,但用更安全的模板元编程和概念来取代 C 语言中容易出错的宏,会让错误较少的代码编程变得更容易。

    1.1K10
    领券