如何实现同时支持对象实例与指针的C++函数模板?
问题:实现同时支持对象实例与指针的函数模板
我需要实现一个可同时处理对象实例和指针的函数模板,这是后续开发可操作元素vector与元素指针vector函数的第一步。当前代码调用print_num传入指针时编译失败,相关代码、编译错误及编译器版本如下:
代码
#include <functional> #include <iostream> struct Foo { int num_ = 42; void print_num() const { std::cout << num_ << std::endl; } }; template<typename T> void print_num(const T & obj) { std::invoke(&T::print_num, obj); } template<typename T> void print_num_ptr(const T * const obj) { std::invoke(&T::print_num, obj); } int main(int argc, char * argv[]) { Foo foo; Foo * foo_ptr = &foo; print_num(foo); // 可正常运行 print_num_ptr(foo_ptr); // 可正常运行 print_num(foo_ptr); // 编译失败 return 0; }
编译错误
foo.cpp:14:18: error: type 'Foo *' cannot be used prior to '::' because it has no members std::invoke(&T::print_num, obj); ^ foo.cpp:30:5: note: in instantiation of function template specialization 'print_num<Foo *>' requested here print_num(foo_ptr); // doesn't work ^ 1 error generated. make[2]: *** [CMakeFiles/foo.dir/foo.cpp.o] Error 1 make[1]: *** [CMakeFiles/foo.dir/all] Error 2 make: *** [all] Error 2
编译器版本
Apple clang version 14.0.3 (clang-1403.0.22.14.1)
Target: x86_64-apple-darwin22.6.0
Thread model: posix
解决思路与修正代码
错误根源
当传入Foo*类型的指针时,模板参数T被推导为Foo*,此时&T::print_num试图访问指针类型的成员,但Foo*本身没有print_num成员,该成员属于底层的Foo类型,因此编译报错。
解决方案
使用C++标准库的类型萃取工具std::remove_pointer_t和std::decay_t获取底层对象类型,再引用该类型的成员函数指针,最后通过std::invoke调用——std::invoke会自动处理对象实例、指针甚至智能指针的调用逻辑。
修正后的代码
#include <functional> #include <iostream> #include <type_traits> struct Foo { int num_ = 42; void print_num() const { std::cout << num_ << std::endl; } }; template<typename T> void print_num(const T & obj) { // 提取底层对象类型,处理对象、指针、引用等情况 using BaseType = std::remove_pointer_t<std::decay_t<T>>; std::invoke(&BaseType::print_num, obj); } int main(int argc, char * argv[]) { Foo foo; Foo * foo_ptr = &foo; print_num(foo); // 正常运行 print_num(foo_ptr); // 现在可正常运行 return 0; }
简化说明
std::decay_t<T>用于处理可能的引用类型,确保得到纯净的类型(如const Foo&会被转换为Foo)std::remove_pointer_t<T>用于将指针类型转换为底层对象类型(如Foo*转换为Foo)- 最终
&BaseType::print_num获取正确的成员函数指针,std::invoke自动处理对象或指针的调用
内容的提问来源于stack exchange,提问作者duncan
相关产品推荐
相关产品推荐

