VS2022中类成员函数指针的返回类型与参数类型推导问题
你遇到的问题其实是C++模板编程里非常常见的「依赖类型名称查找」坑——你的function_properties模板有两个小疏漏,在非模板上下文(比如main函数)里因为类型明确所以没暴露,但到了模板函数testFunction中,依赖模板参数的类型就必须严格遵循规则才行。
问题根源与修复方案
1. 缺失typename导致参数类型推导失败
在function_properties的parameter结构体里,std::tuple_element<index, std::tuple<args...>>::type是依赖类型(依赖于模板参数args...),编译器在模板实例化前无法确定::type是一个类型还是静态成员变量,必须用typename关键字明确告知:
template<size_t index> struct parameter { // 补充typename关键字,标记这是一个类型 using type = typename std::tuple_element<index, std::tuple<args...>>::type; };
2. 模板上下文中的依赖类型必须加typename
在testFunction的if constexpr判断里,function_properties<decltype(method_ptr)>::return_type是依赖于模板参数的嵌套类型,同样需要typename来标记这是一个类型,否则编译器会报错说它不是有效的模板参数:
// 修复后的constexpr判断 if constexpr (std::is_same_v<void, typename function_properties<decltype(method_ptr)>::return_type>) { }
完整修复后的代码
把这两处修改后,你的代码就能正常工作了:
#include <functional> #include <tuple> #include <type_traits> struct testStruct { double testMethod(int, float) { return {}; } }; template<typename F> struct function_properties; template<class C, typename R, typename... args> struct function_properties<R(C::*)(args...)> { using return_type = R; template<size_t index> struct parameter { // 补充typename关键字 using type = typename std::tuple_element<index, std::tuple<args...>>::type; }; }; void testFunction(auto method_ptr, auto& structObj) { typename function_properties<decltype(method_ptr)>::return_type var_0{}; // 正常推导double typename function_properties<decltype(method_ptr)>::parameter<0>::type var_1{}; // 现在能正确推导int了 // 补充typename关键字,修复constexpr判断 if constexpr (std::is_same_v<void, typename function_properties<decltype(method_ptr)>::return_type>) { } auto memFn = std::mem_fn(method_ptr); if constexpr (std::is_same_v<void, decltype(memFn(structObj, 1, 2.3f))>) { } } int main() { testStruct structObj; auto method_ptr = &testStruct::testMethod; typename function_properties<decltype(method_ptr)>::return_type var_0{}; typename function_properties<decltype(method_ptr)>::parameter<0>::type var_1{}; if constexpr (std::is_same_v<void, function_properties<decltype(method_ptr)>::return_type>) { } testFunction(method_ptr, structObj); return 0; }
为什么main函数里原来的代码没问题?
在main函数中,method_ptr是一个auto变量,decltype(method_ptr)是明确的&testStruct::testMethod,属于非依赖类型——编译器在编译main时已经知道它的具体类型,所以不需要typename就能正确识别嵌套的return_type和parameter::type。而在testFunction中,method_ptr是通过模板参数推导出来的,属于依赖类型,必须严格遵循C++的模板依赖类型查找规则,加上typename才能让编译器正确解析。
至于std::mem_fn能正常工作,是因为它的返回类型是标准库精心设计的模板类,其operator()的返回类型在编译时可以被明确推导,而且decltype(memFn(structObj, ...))是一个非依赖类型,所以if constexpr能正常处理。
内容来源于stack exchange

