如何修复自动判断fmt格式化器的C++模板函数逻辑错误?
修复自动适配fmt格式化器的模板函数问题
你的问题核心是模板的SFINAE检测逻辑错误,导致无法正确识别已有fmt格式化器的类型。下面分C++版本给出正确的实现方案:
C++17及以下版本实现
首先定义用于检测类型是否拥有fmt格式化器的特性类,通过std::void_t触发SFINAE:
#include <fmt/format.h> #include <type_traits> // 检测T是否具备可用的fmt格式化器 template <typename T, typename = void> struct has_fmt_formatter : std::false_type {}; template <typename T> struct has_fmt_formatter< T, std::void_t<decltype( fmt::formatter<std::remove_cv_t<T>>{}.format( std::declval<const T&>(), std::declval<fmt::format_context>() ) )> > : std::true_type {}; template <typename T> constexpr bool has_fmt_formatter_v = has_fmt_formatter<T>::value; // 模板函数分支 template <typename T> std::enable_if_t<has_fmt_formatter_v<T>, const T&> log_wrap(const T& arg) { return arg; } template <typename T> std::enable_if_t<!has_fmt_formatter_v<T>, fmt::streamed_view<T>> log_wrap(const T& arg) { return fmt::streamed(arg); }
C++20版本实现(更简洁)
利用C++20的concept特性直接做约束:
#include <fmt/format.h> #include <type_traits> template <typename T> concept has_fmt_formatter = requires(const T& t, fmt::format_context ctx) { fmt::formatter<std::remove_cv_t<T>>{}.format(t, ctx); }; template <has_fmt_formatter T> const T& log_wrap(const T& arg) { return arg; } template <typename T> requires (!has_fmt_formatter<T>) auto log_wrap(const T& arg) { return fmt::streamed(arg); }
关键修复点说明
- 准确的检测逻辑:直接检测
fmt::formatter的format方法是否可调用,而不是仅检测fmt::formatter<T>是否存在——有些类型可能有formatter特化,但因上下文不匹配无法正常格式化,这种检测方式更可靠。 - 处理const/volatile修饰:用
std::remove_cv_t<T>统一处理带const/volatile修饰的类型,避免检测漏判。 - 正确引用fmt上下文:检测时传入
fmt::format_context,匹配fmt格式化器的实际调用场景。
使用示例
在spdlog调用中直接用log_wrap包裹参数即可:
spdlog::info("Log: {}, {}", log_wrap(custom_obj1), log_wrap(custom_obj2));
内容的提问来源于stack exchange,提问作者jjcasmar
相关产品推荐
相关产品推荐

