template <class T> struct has_iterator_typedefs
{
private:
struct __two {char dummy[2];};
template <class U> static __two test( ... );
template <class U> static char test( typename __void_t<typename U::iterator_category>::type* = NULL, //NOTE: require __void_t , == NULL ?
typename __void_t<typename U::difference_type>::type* = NULL,
typename __void_t<typename U::value_type>::type* = NULL,
typename __void_t<typename U::reference>::type* = NULL,
typename __void_t<typename U::pointer>::type* = NULL);
public:
static const bool value = sizeof(test<T>(0,0,0,0,0)) == 1;
};
This is part of libc++ code. I understand how does void_t work, but I don't know why it is required in the context.
Why SFINAE does not work without void_t, like typename U::iterator_category*
?
+) I think it does work w/o default argument = NULL
, is it required?
you cannot have pointer to reference
using X = int&;
using T = X*; // fail
so at least U::reference*
is pretty likely to fail.
I don't think NULL
s are really necessary since the caller do provide all the value.
note: I'm assuming __void_t
is the same as std::void_t