获取类方法返回的std::shared_ptr的element_type的现代C++解决方案
嗨,我来帮你搞定这个问题!你遇到的问题主要有两个关键点:一是std::result_of的使用细节没处理好,二是它在C20已经被弃用了,咱们用现代C的标准工具来解决会更顺畅。
先说说你当前代码里的问题:你写decltype(result)::element_type是错误的,因为result本身就是一个类型别名,而decltype()是用来获取表达式的类型的——你直接写result::element_type就够了,但这里还有个小坑:result是const std::shared_ptr<A>&(引用类型),引用本身没有element_type成员,得先把引用和顶层const去掉,才能拿到底层的std::shared_ptr<A>类型。
下面给你两种现代C的解决方案,覆盖C17及以上版本:
方案一:用std::invoke_result_t(替代弃用的std::result_of)
std::invoke_result_t是C++17引入的,专门用来推导可调用对象的返回类型,完美替代std::result_of。代码示例如下:
#include <memory> #include <type_traits> class A {}; class B { public: // 注意:成员函数要设为public,否则外部无法获取方法指针 const std::shared_ptr<A> foo() const; }; // 推导B::foo的返回类型 using MethodReturnType = std::invoke_result_t<decltype(&B::foo), const B&>; // 去掉返回类型的引用和顶层const,拿到纯净的std::shared_ptr<A> using UnderlyingPtrType = std::remove_cv_t<std::remove_reference_t<MethodReturnType>>; // 提取element_type,这就是你要的A类型 using ElementType = UnderlyingPtrType::element_type;
解释一下:
std::invoke_result_t<Callable, Args...>会模拟调用Callable并传入Args参数,返回对应的结果类型。这里因为foo是const成员函数,所以要传const B&作为实例参数。std::remove_reference_t用来去掉返回类型的引用,std::remove_cv_t去掉顶层的const/volatile,这样就得到了std::shared_ptr<A>类型,自然就能访问它的element_type了。
方案二:直接用decltype+std::declval推导返回类型
这种方式更直观,不需要借助成员函数指针,直接模拟调用成员函数来获取返回类型:
#include <memory> #include <type_traits> class A {}; class B { public: const std::shared_ptr<A> foo() const; }; // 用std::declval创建一个const B的"虚拟实例",调用foo后用decltype获取返回类型 using MethodReturnType = decltype(std::declval<const B>().foo()); // 同样去掉引用和顶层const using UnderlyingPtrType = std::remove_cv_t<std::remove_reference_t<MethodReturnType>>; using ElementType = UnderlyingPtrType::element_type;
解释:
std::declval<T>()可以在不需要真正实例化T的情况下,生成一个T类型的右值引用,刚好用来模拟调用成员函数,非常适合推导返回类型。
额外简化(C++20及以上)
如果你的编译器支持C++20,可以用std::unwrap_reference_t简化去掉引用的步骤,或者直接用std::decay_t一次性处理引用和const:
// 用unwrap_reference_t替代remove_reference_t using UnderlyingPtrType = std::remove_cv_t<std::unwrap_reference_t<MethodReturnType>>; // 或者用decay_t一步到位(会同时处理引用、const、volatile,以及数组/函数转指针) using UnderlyingPtrType = std::decay_t<MethodReturnType>;
最后再提一句:你之前用std::result_of<decltype(method)(B)>::type得到引用类型,是因为调用成员函数指针时,传入的B对象会被绑定到引用参数,所以返回类型是引用。只要调整参数为const B&,或者后续去掉引用,就能正确拿到shared_ptr类型啦。
备注:内容来源于stack exchange,提问作者Foaly

