iterator_traits SFINAE友好

时间:2018-03-13 15:41:46

标签: c++ typetraits

从cppreference

阅读excerpt
  

如果Iterator没有五种成员类型difference_typevalue_typepointerreferenceiterator_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>);
}

Live

这是为什么?如果他们彼此独立,我会认为它更友好。例如,如果算法只需要在某处存储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;

,则会成功

1 个答案:

答案 0 :(得分:0)

可以从相应的提案N3844收集一些见解:

  

事后看来,它不时被人们争论   SGI STL(以及C ++ 98)在指定时出错   iterator_traits是一个由五个类型别名组成的捆绑包   与迭代器相关的特性本来是一个更好的设计。即使是真的,   本文提出的基本捆绑设计没有变化,保持不变   一个全有或全无的原则。

所以看起来只是试图非常谨慎地接近目前的情况,并做出使SFINAE友好的特性所需的最小变化。选择性地包括该成员将导致半定义的特征,显然,这被认为是一个潜在的深远结果。