编译器: MSVC v142
所属文件: xutility
位置(行): 259
函数名称:_Unwrappable
函数描述:
_Unwrappable
函数的作用是检查T
是否同时具有_Unwrapped
和_Seek_to
函数, 以及确保_Unwrapped
可以作为参数传递给_Seek_to
. 如果两个条件都满足, 那么它就是一个_Unwrappable
对象, 即: 是一个迭代器.
源码:
// FUNCTION TEMPLATE _Get_unwrapped
template <class _Iter, class = void>
struct _Unwrappable : false_type {};
template <class _Iter>
struct _Unwrappable<_Iter, void_t<decltype(_STD declval<_Iter&>()._Seek_to(_STD declval<const _Iter&>()._Unwrapped()))>>
: _Allow_inheriting_unwrap<_Iter>::type {};
模板匹配
void_t<decltype(_STD declval<_Iter&>()._Seek_to(_STD declval<const _Iter&>()._Unwrapped()))
, 又长又臭的过滤条件.
C++
对待模板的套路就是利用 SFINAE
的失败不会退出编译而是跳过当前匹配的原则, 也就是说如果当前函数匹配过程出现任何失败, 就表示这个T
不是一个Iterator
对象.
void_t
不管你返回的是什么类型,反正它永远都是void, 它就是一个垃圾箱, 用它只是因为它提供了接受任何类型参数, 正好可以利用这个机制把尖角括号内部的表达式消化掉, 出错就跳过当前匹配,不出错就表示第二个模板参数是一个void
.
decltype
和declval
搭配起来就是我可以不用实例化这个对象就可以检查这个对象的某个方法返回的是什么类型(备注: 不执行函数
), 这里使用它们这个组合有两个目的, 一是检查这个T
是否有_Seek_to
方法和_Unwrapped
方法, 二是检查_Seek_to
的参数要求的类型跟_Unwrapped
返回的类型是否对的上. 这两步检查任何一个步骤出错,_Unwrappable
函数就认为T
不是一个Iterator
.
TODO: 为什么这里要检查两个成员函数, 直接检查_Unwrapped函数不就完事了吗?
继承
_Unwrappable
继承了 _Allow_inheriting_unwrap<_Iter>::type
, 继承过程中又再做了一层筛选, 主要是证明Iterator
的类别一致, 即证明你就是你.
template <class _Iter, class = void>
struct _Allow_inheriting_unwrap : true_type {};
template <class _Iter>
struct _Allow_inheriting_unwrap<_Iter, enable_if_t<!is_same_v<_Iter, typename _Iter::_Prevent_inheriting_unwrap>>>
: false_type {};