Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iterator_traits SFINAE friendliness

Tags:

c++

typetraits

When reading the excerpt from cppreference

If Iterator does not have the five member types difference_type, value_type, pointer, reference, and iterator_category, then this template has no members by any of those names (std::iterator_traits is SFINAE-friendly)

I automatically thought it meant each member type is defined when they are defined in the iterator itself. But lo and behold, it actually meant if all five are defined, then they are defined.

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

Why is this? I would've thought it is friendlier if they were independent of each other. For example if an algorithm just needs to store the value_type somewhere and doesn't care about anything else.

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;
}

It will fail to compile on some iterator that only defined value_type, but funnily enough, succeed if it were instead typename It::value_type v;

like image 459
Passer By Avatar asked Nov 08 '22 09:11

Passer By


1 Answers

Some insight can be gathered from corresponding proposal N3844:

With benefit of hindsight, it has from time to time been argued that the SGI STL (and consequently C++98) erred in specifying iterator_traits as a bundle of five type aliases, and that individual iterator-related traits would have been a better design. Even if true, this paper proposes no change to the basic bundled design, keeping to an all-or-nothing principle.

So it looks like it was just to try to approach the current situation very cautiously and make the minimum change required to make the traits SFINAE-friendly. Selective inclusion of the member would lead to the half-defined traits, and apparently, this was considered a potentially far-reaching result.

like image 69
SergeyA Avatar answered Nov 14 '22 23:11

SergeyA