C++17编译时判断shared_ptr底层类型foo方法的参数适配性
问题描述
现有如下C++17代码:
template <typename T> using ptr_t = std::shared_ptr<const T>; class some_type; class A { some_type foo() const; }; class B { some_type foo() const; }; class C { some_type foo(int) const; }; std::variant<ptr_t<A>, ptr_t<B>, ptr_t<C>> var;
需要给这个std::variant编写一个visitor,在编译时判断每个shared_ptr指向的底层类型的foo方法是否能接受int参数,从而自动选择调用foo(15)还是无参的foo()。visitor框架如下:
struct visitor { template <typename T> ptr_t<some_type> operator()(const T& config) const { if constexpr (/* 此处需编写判断逻辑 */) return config->foo(15); else return config->foo(); } };
其中模板参数T为ptr_t<A>、ptr_t<B>或ptr_t<C>类型。
解决方案
可以借助C++17的constexpr特性与标准库类型 trait,实现编译期的方法可调用性检测。核心是先提取shared_ptr的底层元素类型,再判断该类型的foo方法是否支持传入int参数。
完整的visitor实现如下:
#include <memory> #include <variant> #include <type_traits> template <typename T> using ptr_t = std::shared_ptr<const T>; class some_type; class A { some_type foo() const; }; class B { some_type foo() const; }; class C { some_type foo(int) const; }; struct visitor { template <typename T> ptr_t<some_type> operator()(const T& config) const { // 提取shared_ptr指向的底层元素类型 using ElementType = typename T::element_type; // 编译期检测:const ElementType*调用foo(int)是否合法,且返回值为some_type if constexpr (std::is_invocable_r_v<some_type, decltype(&ElementType::foo), const ElementType*, int>) return config->foo(15); else return config->foo(); } };
逻辑说明
- 提取底层类型:通过
typename T::element_type获取shared_ptr包裹的原始类型(如A、B、C)。 - 编译期检测:
std::is_invocable_r_v是C++17提供的类型 trait,用于验证:以指定参数调用目标可调用对象时,是否合法且返回值可转换为指定类型。- 此处验证的是:
ElementType的foo成员函数,在const ElementType*(对应config->的指针类型)上调用时,能否接受一个int参数,且返回值为some_type。 - 检测结果为
true时编译带参调用分支,否则编译无参调用分支。
如果可以使用C++20,还能通过更直观的requires表达式简化判断:
if constexpr (requires(const ElementType& obj) { obj.foo(15); })
内容的提问来源于stack exchange,提问作者M.K.
相关产品推荐
相关产品推荐

