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

C++可变参数模板log函数重载歧义问题求解

解决ClogLogger::log模板重载歧义问题

问题根源

调用log(0, "{} {}", "foo_1", "foo_2")时,编译器可将第二个字符串参数推导为带异常重载的exceptionType模板参数,此时两个重载都能匹配参数列表,导致错误选择带异常的版本,进而因字符串无what()成员函数引发调用错误。

解决方案

通过SFINAE机制限制带异常的重载仅接受std::exception或其子类类型,让字符串字面量无法匹配该重载,编译器会自动选择不带异常的版本。

方法1:C++17及更早版本(使用std::enable_if)

需包含<type_traits>头文件,修改带异常的log函数:

#include <type_traits>

// 不带异常的log函数(保持不变)
template<typename levelType, typename formatType, typename ... variadicParamsType> 
void ClogLogger::log(levelType level, formatType format, variadicParamsType... formatParams)
{
   string levelHeader = getLevelHeader(level);
   clog << levelHeader << fmt::format(format, formatParams...) << endl;
}

// 带异常的log函数(添加SFINAE约束)
template<typename levelType, class exceptionType, typename formatType, typename ... variadicParamsType> 
std::enable_if_t<std::is_base_of_v<std::exception, std::decay_t<exceptionType>>>
ClogLogger::log(levelType level, exceptionType e, formatType format, variadicParamsType ... formatParams)
{
   string levelHeader = getLevelHeader(level);
   clog << levelHeader << fmt::format(format, formatParams...) << endl;
   THROW_MYEXCEPTION(e.what());// 自定义宏
}

方法2:C++20及以上版本(使用requires表达式)

requires表达式让约束更直观,代码可读性更高:

#include <type_traits>

// 不带异常的log函数(保持不变)
template<typename levelType, typename formatType, typename ... variadicParamsType> 
void ClogLogger::log(levelType level, formatType format, variadicParamsType... formatParams)
{
   string levelHeader = getLevelHeader(level);
   clog << levelHeader << fmt::format(format, formatParams...) << endl;
}

// 带异常的log函数(添加requires约束)
template<typename levelType, class exceptionType, typename formatType, typename ... variadicParamsType> 
void ClogLogger::log(levelType level, exceptionType e, formatType format, variadicParamsType ... formatParams)
requires std::is_base_of_v<std::exception, std::decay_t<exceptionType>>
{
   string levelHeader = getLevelHeader(level);
   clog << levelHeader << fmt::format(format, formatParams...) << endl;
   THROW_MYEXCEPTION(e.what());// 自定义宏
}

原理说明

  • std::is_base_of_v<std::exception, std::decay_t<exceptionType>>用于检查exceptionType是否是std::exception的子类(std::decay_t处理可能的引用/const限定符)。
  • 当传入参数不是异常类型时,带异常的重载会因模板替换失败被排除出候选函数列表,编译器会自动选择不带异常的版本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 11:42:35