Andrey Semashev wrote:
I can reproduce it locally with clang 3.4. Shows only
with -std=c++11 -stdlib=libc++. Trying to dig further.
Ah. Sneaky hobbits. Conforming extension my posterior. :-)
(Actually, it _is_ a conforming extension, by a strict reading of the
standard. Still, I'd have preferred a little less cleverness.)
template <class _Tp>
struct __has_iterator_category
{
private:
struct __two {char __lx; char __lxx;};
template <class _Up> static __two __test(...);
template <class _Up> static char __test(typename _Up::iterator_category*
= 0);
public:
static const bool value = sizeof(__test<_Tp>(0)) == 1;
};
template struct __iterator_traits_impl {};
template <class _Iter>
struct __iterator_traits_impl<_Iter, true>
{
typedef typename _Iter::difference_type difference_type;
typedef typename _Iter::value_type value_type;
typedef typename _Iter::pointer pointer;
typedef typename _Iter::reference reference;
typedef typename _Iter::iterator_category iterator_category;
};
template struct __iterator_traits {};
template <class _Iter>
struct __iterator_traits<_Iter, true>
: __iterator_traits_impl
<
_Iter,
is_convertible::value ||
is_convertible::value
>
{};
// iterator_traits<Iterator> will only have the nested types if
Iterator::iterator_category
// exists. Else iterator_traits<Iterator> will be an empty class. This
is a
// conforming extension which allows some programs to compile and behave
as
// the client expects instead of failing at compile time.
template <class _Iter>
struct _LIBCPP_TYPE_VIS_ONLY iterator_traits
: __iterator_traits<_Iter, __has_iterator_category<_Iter>::value> {};