从cppreference
阅读excerpt时如果
Iterator
没有五种成员类型difference_type
,value_type
,pointer
,reference
和iterator_category
,那么此模板没有任何成员的名字(std::iterator_traits
是SFINAE友好的)
我自动认为这意味着在迭代器本身定义每个成员类型时都会定义它们。但是,实际上,如果所有五个被定义,那么它们就被定义了。
struct defined
{
using difference_type = int;
using value_type = int;
using pointer = int*;
using reference = int&;
using iterator_category = std::input_iterator_tag;
};
struct undefined
{
using value_type = int;
};
template<typename T>
using value_type = typename std::iterator_traits<T>::value_type;
void foo()
{
using std::experimental::is_detected_v;
static_assert(is_detected_v<value_type, defined>);
static_assert(!is_detected_v<value_type, undefined>);
}
这是为什么?如果他们彼此独立,我会认为它更友好。例如,如果算法只需要在某处存储value_type
并且不关心其他任何事情。
template<typename It>
auto amazingfy(It first, It last)
{
typename std::iterator_traits<It>::value_type v;
for(; first != last; first++)
v += *first;
return v;
}
它将无法在仅定义value_type
的某个迭代器上进行编译,但有趣的是,如果它是typename It::value_type v;
答案 0 :(得分:0)
可以从相应的提案N3844收集一些见解:
事后看来,它不时被人们争论 SGI STL(以及C ++ 98)在指定时出错 iterator_traits是一个由五个类型别名组成的捆绑包 与迭代器相关的特性本来是一个更好的设计。即使是真的, 本文提出的基本捆绑设计没有变化,保持不变 一个全有或全无的原则。
所以看起来只是试图非常谨慎地接近目前的情况,并做出使SFINAE友好的特性所需的最小变化。选择性地包括该成员将导致半定义的特征,显然,这被认为是一个潜在的深远结果。