You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现自动切换cout/printf的C++可变参数LOG宏

实现支持双模式的C++ LOG宏

核心思路

要实现同时支持流式输出(<<)和格式化输出(类似printf)的LOG宏,核心是利用函数重载区分不同调用场景,配合宏的参数个数判断来分发到对应的处理逻辑:

  • 无参数或单个参数(包括流式表达式):转发给std::cout处理
  • 多参数(格式串+变量):转发给printf处理

完整实现代码

#include <iostream>
#include <cstdio>
#include <utility>
#include <type_traits>

// 流式输出辅助类:负责处理LOG << ... << ...的链式调用
class LogHelper {
public:
    template<typename T>
    LogHelper& operator<<(T&& val) {
        std::cout << std::forward<T>(val);
        return *this;
    }

    // 析构时自动添加换行,统一输出格式
    ~LogHelper() {
        std::cout << '\n';
    }
};

// 处理多参数场景:格式串+变量,转发给printf
template<typename... Args, typename = std::enable_if_t<(sizeof...(Args) > 0)>>
void log_impl(const char* fmt, Args&&... args) {
    printf(fmt, std::forward<Args>(args)...);
    putchar('\n');
}

// 处理单个字符串参数:直接用cout输出
void log_impl(const char* msg) {
    std::cout << msg << '\n';
}

// 处理单个非字符串参数:比如数字、对象等,用cout输出
template<typename T>
std::enable_if_t<!std::is_same_v<std::decay_t<T>, const char*>, void> log_impl(T&& val) {
    std::cout << std::forward<T>(val) << '\n';
}

// 处理无参数场景:返回LogHelper对象,支持链式<<调用
LogHelper log_impl() {
    return LogHelper();
}

// 宏分发逻辑:根据参数个数选择对应的处理函数
#define LOG(...) _LOG_DISPATCH(__VA_ARGS__)

#define _LOG_DISPATCH(...) \
    _LOG_IF_HAS_ARGS(__VA_ARGS__, _LOG_HAS_ARGS, _LOG_NO_ARGS)(__VA_ARGS__)

#define _LOG_IF_HAS_ARGS(_1, ...) _LOG_HAS_ARGS

#define _LOG_HAS_ARGS(...) log_impl(__VA_ARGS__)
#define _LOG_NO_ARGS() log_impl()

测试用例

int main() {
    // 单个字符串参数:用cout输出
    LOG("This is a single message");

    // 多参数格式化:用printf输出
    LOG("Number: %d, String: %s", 123, "test");

    // 流式调用:用cout输出,自动加换行
    LOG << "Stream" << " output" << ", number: " << 456;

    // 单个非字符串参数:用cout输出
    LOG(789);

    return 0;
}

关键细节说明

  1. 参数个数判断:通过宏_LOG_IF_HAS_ARGS判断是否有传入参数,无参数时返回LogHelper对象支持流式调用,有参数时转发给对应的log_impl重载。
  2. 重载区分:
    • 多参数版本通过std::enable_if限制仅当参数个数>0时生效,避免和单个字符串参数的重载冲突。
    • 单个参数版本区分字符串和非字符串类型,确保都用cout输出。
  3. 自动换行:流式调用通过LogHelper的析构函数自动添加换行,格式化调用则手动添加,保证所有输出风格统一。

内容的提问来源于stack exchange,提问作者XORer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 07:47:38