C++使用source_location时operator=模板参数推导失败求助
解决赋值运算符模板参数无法自动推导的问题
问题背景
开发日志库时,希望在调用赋值函数时自动将std::source_location::current()作为默认参数传递。现有代码中,显式指定模板参数调用赋值运算符可以正常运行,但直接使用a = 1.0这类简洁写法会报错,提示无法推导模板参数T。
原始代码
#include <iostream> #include <source_location> #include <type_traits> template <class T> struct log_helper { log_helper(const T& o, std::source_location sl = std::source_location::current()) : value(o), sl(sl) {} T value; std::source_location sl; }; struct ratio_t { operator double() const { return ratio; } template<class T, class = typename std::enable_if_t<std::is_arithmetic_v<T>>> ratio_t& operator=(const log_helper<std::type_identity_t<T>>& o) { ratio = o.value; line = o.sl.line(); func = o.sl.file_name(); printf("file: %s line: %d\n", func.c_str(), line); return *this; } void clear() { ratio = 0.0f; line = 0; func.clear(); } double get_ratio() const { return ratio; } uint32_t get_line() const { return line; } std::string get_func() const { return func; } private: double ratio{0.0f}; uint32_t line{0}; std::string func; }; int main() { ratio_t a; // a.operator=<double>(log_helper(1.0)); // a.operator=<double>(1.0); // 可以正常运行 a = 1.0; // <- 此处报错 }
错误信息
b.cpp: In function 'int main()': b.cpp:61:9: error: no match for 'operator=' (operand types are 'ratio_t' and 'double') 61 | a = 1.0; | ^~~ b.cpp:23:14: note: candidate: 'template<class T, class> ratio_t& ratio_t::operator=(const log_helper<typename std::type_identity<_Tp>::type>&)' 23 | ratio_t& operator=(const log_helper<std::type_identity_t<T>>& o) { | ^~~~~~~~ b.cpp:23:14: note: template argument deduction/substitution failed: b.cpp:61:9: note: couldn't deduce template parameter 'T' 61 | a = 1.0; | ^~~ b.cpp:13:8: note: candidate: 'ratio_t& ratio_t::operator=(const ratio_t&)' 13 | struct ratio_t { | ^~~~~~~ b.cpp:13:8: note: no known conversion for argument 1 from 'double' to 'const ratio_t&' b.cpp:13:8: note: candidate: 'ratio_t& ratio_t::operator=(ratio_t&&)' b.cpp:13:8: note: no known conversion for argument 1 from 'double' to 'ratio_t&&'
错误原因
模板参数推导过程中,编译器不会自动将double这类算术类型隐式转换为log_helper<double>来匹配赋值运算符的参数类型,因此无法推导模板参数T。只有当实参类型与函数参数类型完全匹配(或仅涉及内置转换)时,模板参数才能被自动推导。
解决方案
修改ratio_t的赋值运算符,让它直接接受算术类型T的参数,在函数内部构造log_helper<T>以自动获取当前的source_location。这样模板参数T可以直接从赋值右侧的实参推导出来,同时满足日志记录需求。
修改后的代码
#include <iostream> #include <source_location> #include <type_traits> template <class T> struct log_helper { log_helper(const T& o, std::source_location sl = std::source_location::current()) : value(o), sl(sl) {} T value; std::source_location sl; }; struct ratio_t { operator double() const { return ratio; } // 修改后的赋值运算符:直接接受算术类型T template<class T, class = std::enable_if_t<std::is_arithmetic_v<T>>> ratio_t& operator=(const T& val) { log_helper<T> helper(val); // 自动获取当前source_location ratio = helper.value; line = helper.sl.line(); func = helper.sl.file_name(); printf("file: %s line: %d\n", func.c_str(), line); return *this; } void clear() { ratio = 0.0f; line = 0; func.clear(); } double get_ratio() const { return ratio; } uint32_t get_line() const { return line; } std::string get_func() const { return func; } private: double ratio{0.0f}; uint32_t line{0}; std::string func; }; int main() { ratio_t a; a = 1.0; // 现在可以正常运行 a = 42; // 也支持整数类型 }
说明
- 修改后的赋值运算符直接接收
T类型参数,模板参数T能从右侧实参(如1.0、42)自动推导。 - 在函数内部构造
log_helper<T>时,会自动使用默认参数std::source_location::current()获取当前代码位置,完美实现日志记录需求。 - 保留了
std::enable_if_t<std::is_arithmetic_v<T>>的约束,确保只有算术类型能触发这个赋值运算符。
内容的提问来源于stack exchange,提问作者xujh
相关产品推荐
相关产品推荐

