源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

C++ 11实现检查是否存在特定的成员函数

  • 时间:2021-03-20 17:17 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:C++ 11实现检查是否存在特定的成员函数
[b]问题提出[/b] 最近工作中遇到这样一个需求:实现一个ToString函数将类型T转换到字符串,如果类型T中含有同名方法ToString则直接调用。 这样一个ToString实现可以使用[code]std::enable_if[/code]来做到,但是这里的难点在于如何判断类型T中存在这样一个ToString方法,以便可以放入enable_if中做SFINAE。 [b]检查类中是否存在特定成员[/b] 相同的问题在知乎上有人提出过,@孙明琦的答案提供了一个用于检测特定检测子U在类型T下是否有效的检测器is_detected_v。其中用到了一个C++17的[code]std::void_t[/code],考虑到目前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
{};
简单分析可以看到[code]__is_swappable[/code]被用来检查是否存在一个[code]swap[/code]函数接受T作为参数,很有趣的是[code]__test[/code]函数,如果存在swap函数满足条件,那么[code]test(int)[/code]这个重载版本就会被选中。而如果不满足条件,因为推导失败就剩下了test(…)这个版本。通过这一手段,再设置下返回值分别为[code]true[/code]和[code]false[/code],就实现了这样的一个检测过程。 按图索骥,检查是否存在成员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))
{};
[code]HasMemberToString::value[/code]就是T中是否存在该成员的计算结果。 [b]检测是否存在特定成员函数[/b] 但是上述代码有个问题,如果类T中的ToString是个成员变量,上述检测也会返回true。 解决这一问题的手段是去调用[code]T::ToString[/code],如果这个ToString可以被调用并能生成返回值,就认为这是个成员函数(严谨的讲,这个过程是确认[code]T::ToString[/code]是callable的,但是callable的玩意不一定就是成员函数,然而实际使用并不需要这样细分)。 这里的另一个问题是,因为ToString是成员函数,那么[code]decltype(T::ToString())[/code]这种手段就行不通了,因为成员函数必须带对象进行调用。既然必须要一个对象,那么这里的解决方法就是用上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。 [b]总结[/b] 以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对编程素材网的支持。
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部