使用可变参数模板打印函数签名时丢失const限定符的问题排查
问题原因
当函数参数是值传递的const类型(顶层const)时,C++会将其视为与非const值参数等价的函数签名。在模板推导Ret(*)(Args...)时,编译器会自动丢弃顶层const,导致Args中的类型丢失了const限定符。
而手动调用print_function_args<const int>()时,模板参数直接指定为const int,没有经过函数类型推导的“顶层const丢弃”步骤,所以能正常识别const。
解决办法
通过自定义类型萃取工具,直接从函数的原始声明类型中提取参数类型(包括顶层const),避免依赖函数指针推导时的const丢失。
修改后的完整代码
#include <iostream> #include <type_traits> #include <tuple> // 类型萃取工具:提取函数的参数和返回值类型 template <typename T> struct function_traits; // 匹配普通函数类型 template <typename Ret, typename... Args> struct function_traits<Ret(Args...)> { static constexpr size_t arity = sizeof...(Args); using return_type = Ret; template <size_t N> using arg_type = std::tuple_element_t<N, std::tuple<Args...>>; }; // 匹配函数指针类型 template <typename Ret, typename... Args> struct function_traits<Ret(*)(Args...)> : function_traits<Ret(Args...)> {}; template <typename T> void print_type_info() { if (std::is_const_v<T>) { std::cout << "const "; } std::cout << typeid(T).name() << std::endl; } // 递归打印参数类型的辅助函数 template <typename Traits, size_t N = 0> void print_function_args_impl() { if constexpr (N < Traits::arity) { print_type_info<typename Traits::template arg_type<N>>(); print_function_args_impl<Traits, N + 1>(); } } template <typename Func> void print_function_signature(Func) { using traits = function_traits<Func>; print_function_args_impl<traits>(); } void my_function(int, const int) {} int main() { print_function_signature(my_function); // 现在会打印'i'和'const i' print_function_args<const int>(); // 正常打印'const i' return 0; }
修改说明
- 新增
function_traits结构体,用于从函数类型/函数指针中提取参数类型,完整保留原始声明中的顶层const。 - 将
print_function_signature改为接受任意函数类型的模板参数,通过function_traits获取参数类型,绕开了会丢失const的函数指针推导逻辑。 - 使用递归的
print_function_args_impl遍历所有参数类型并完成打印。
内容的提问来源于stack exchange,提问作者Donald Ninetyfive
相关产品推荐
相关产品推荐

