C++ 11实现检查是否存在特定的成员函数
2017-02-24 14:10
651 查看
问题提出
最近工作中遇到这样一个需求:实现一个ToString函数将类型T转换到字符串,如果类型T中含有同名方法ToString则直接调用。
这样一个ToString实现可以使用
std::enable_if来做到,但是这里的难点在于如何判断类型T中存在这样一个ToString方法,以便可以放入enable_if中做SFINAE。
检查类中是否存在特定成员
相同的问题在知乎上有人提出过,@孙明琦的答案提供了一个用于检测特定检测子U在类型T下是否有效的检测器is_detected_v。其中用到了一个C++17的
std::void_t,考虑到目前C++17还没得用,这个实现只作参考之用(事实上C++17自带了一个这样的检测器,并不需要自己写这样的模板)。
经人提醒,我参考了下标准库在实现swap上做的努力,看到了这样的写法:
namespace __swappable_details { using std::swap; struct __do_is_swappable_impl { template <typename _Tp, typename = decltype(swap(std::declval<_Tp&>(), std::declval<_Tp&>()))> static true_type __test(int); template <typename> static false_type __test(...); }; } template <typename _Tp> struct __is_swappable_impl : public __swappable_details::__do_is_swappable_impl { typedef decltype(__test<_Tp>(0)) type; }; template <typename _Tp> struct __is_swappable : public __is_swappable_impl<_Tp>::type {};
简单分析可以看到
__is_swappable被用来检查是否存在一个
swap函数接受T作为参数,很有趣的是
__test函数,如果存在swap函数满足条件,那么
test(int)这个重载版本就会被选中。而如果不满足条件,因为推导失败就剩下了test(…)这个版本。通过这一手段,再设置下返回值分别为
true和
false,就实现了这样的一个检测过程。
按图索骥,检查是否存在成员ToString的模板就可以这么写:
namespace details { struct HasMemberToStringValidator { template <typename T, typename = decltype(&T::ToString)> static std::true_type Test(int); template <typename> static std::false_type Test(...); }; } template <typename T> struct HasMemberToString : public decltype(details::HasMemberToStringValidator::Test<T>(0)) {};
HasMemberToString::value就是T中是否存在该成员的计算结果。
检测是否存在特定成员函数
但是上述代码有个问题,如果类T中的ToString是个成员变量,上述检测也会返回true。
解决这一问题的手段是去调用
T::ToString,如果这个ToString可以被调用并能生成返回值,就认为这是个成员函数(严谨的讲,这个过程是确认
T::ToString是callable的,但是callable的玩意不一定就是成员函数,然而实际使用并不需要这样细分)。
这里的另一个问题是,因为ToString是成员函数,那么
decltype(T::ToString())这种手段就行不通了,因为成员函数必须带对象进行调用。既然必须要一个对象,那么这里的解决方法就是用上declval来产生一个对象,再用decltype获取返回值类型。
按照这个思路,验证过程被改动成:
struct HasMemberToStringValidator { template <typename T, typename U = typename std::decay<decltype(std::declval<T>().ToString())>::type, typename = typename std::enable_if<std::is_same<std::string, U>::value>::type> static std::true_type Test(int); template <typename> static std::false_type Test(...); };
这个升级版本除了能检查是否存在成员函数ToString以外还对返回值做了限定,确保返回的是string。以此类推,还能检查返回是否是u16string、u32string。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。
您可能感兴趣的文章:
相关文章推荐
- c++ 检查是否存在成员函数
- (SFINAE)C++检查成员函数是否存在
- C++中类成员函数未实现,是否能够编译链接通过?
- asp实现检查目录是否存在与建立目录的函数
- C++检查某个文件或目录是否存在的函数
- asp实现检查目录是否存在与建立目录的函数
- 能实现检查窗口是否存在的函数
- C++泛型编程技巧 - 如何判断输入类型是否定义了特定的成员函数
- C++中类成员函数未实现,是否能够编译链接通过?
- php函数(检查变量、函数、键是否存在)
- 深入理解C++对象模型-成员函数的本质以及虚函数的实现(非虚继承)
- 回调函数的C++ 封装(非静态成员函数的回调函数实现方法)
- 通过文件锁实现,程序开始运行时,先判断文件是否存在,若存在则表明该程序已经在运行了,如果不存在就用open函数创建该文件,程序退出时关闭文件并删除文件
- php-Arrays 函数-array_key_exists-检查给定的键名或索引是否存在于数组中
- PHP - Manual手册 - 函数参考 - Filesystem 文件系统函数 - file_exists检查文件或目录是否存在
- C++第六周任务5:解决用一个项目多个文件的方式实现,其中两个类的声明放在一个.h文件中,每个类的成员函数分别放一个文件,main()函数用一个文件。体会这样安排的优点。
- php file_exists 检查文件或目录是否存在的函数
- C++ 实现把非静态成员函数作为回调函数(非static)(转 待研究)
- C++学习总结_成员函数的声明和实现需要注意问题
- asp下检查表中是否存在某个字段(列)函数