如何在C++中检测函数模板及特定签名函数的存在?
检测类是否存在特定签名的成员函数(含模板函数)
是否存在一种方法,可检测具有特定签名的函数(无论是否为模板函数)是否存在?
示例代码如下:
template <bool FLAG> class A { public: template <bool FLAG_ = FLAG> std::enable_if_t<FLAG_, float> run(float a, float b) { return a + b; } }; class B { public: float run(float a, float b) { return a + b; } };
需要编写一个通用特性HasRun,实现如下判定:
HasRun<A<true>>::value; // 返回true HasRun<A<false>>::value; // 返回false HasRun<B>::value; // 返回true
我了解针对非模板成员函数的可行方案:
template <typename T, typename = void> struct HasRun : std::false_type { }; template <typename T> struct HasRun<T, std::enable_if_t<std::is_member_function_pointer<decltype(&T::run)>::value>> : std::true_type { };
但该方案仅适用于B类。
如果调整为:
template <typename T> struct HasRun<T, std::enable_if_t<std::is_member_function_pointer<decltype(&T::template run<true>)>::value>> : std::true_type { };
则仅适用于A<true>,无法适配B类,还会错误判定A<false>拥有run()方法(实际A<false>::run()并未实例化)。
解决方案
正确的做法是利用SFINAE特性,通过尝试调用目标函数的表达式来检测,既能适配普通成员函数,也能适配带默认模板参数的成员模板函数,同时会考虑enable_if的实例化约束。
实现代码如下:
#include <type_traits> template <typename T, typename = void> struct HasRun : std::false_type {}; template <typename T> struct HasRun<T, std::void_t< decltype(std::declval<T>().run(std::declval<float>(), std::declval<float>())) >> : std::true_type {};
原理说明
std::void_t会推导括号内表达式的有效性:如果T的实例可以调用run(float, float)(无论是普通成员函数,还是能被正确实例化的模板成员函数),则特化版本被选中,value为true;否则回退到基类的false_type。- 对于
A<false>,其run模板函数因enable_if_t<FLAG_>的约束(FLAG_默认是false)无法被实例化,表达式std::declval<A<false>>().run(...)触发SFINAE,特化版本不生效,最终value为false。 - 对于B类,普通成员函数
run存在且签名匹配,特化版本生效,value为true。 - 对于
A<true>,模板成员函数能被正常实例化,表达式有效,value为true。
内容的提问来源于stack exchange,提问作者zhanginou
相关产品推荐
相关产品推荐

