简体   繁体   中英

Defining a custom iterator traits for a generic function

I'm trying to write a generic function which will derive a return type at compile time according to the iterator it is given. Usually this is done through std::iterator_traits, but I also wanted to define my own version of iterator_traits, called my_iterator traits. Here's my code:

#include <cassert>
#include <iterator>
#include <vector>

using namespace std;

template <typename I>
struct my_iterator_traits {
    typedef typename I::value_type                     value_type;
    typedef typename I::iterator_category       iterator_category;
};

template <typename T>
struct my_iterator_traits<T*> {
    typedef T                                         value_type;
    typedef std::random_access_iterator_tag    iterator_category;
};                                                               

template <typename II>
typename my_iterator_traits<II>::value_type f(II b, II e) {
    typename my_iterator_traits<II>::value_type val = 0;
    return val;
}

int main () {
    int a[] = {2, 3, 4};
    int i = f(a, a + 3);

    assert(i == 0);

    // vector<int> v = {2};
    // f(v.begin(), v.end());

    // assert(j == 0);
    return 0;
}

Everything up to and including the main function and the function f() makes perfect sense. In main, I make an int array, call f() on it, and confirm that the output I get is an int whose value is zero.

What isn't clear is the following. I have two templates up top followed by the struct keyword. It would make perfect sense to use the second one (the one that takes in T* as the template argument). Specifically, why do we need the first struct template (the one without template parameters)? More importantly, what is the relationship between the two struct templates?

The first is the declaration of the template and the second is a partial specialization of the first. Partial specialization like explained in the link can have customization of the template parameter (ex: some fixed parameters, some restriction of what parameter your are referring (pointer, references, etc...), etc...).

The first template<typename>struct is a template , the second is a specialization of the first template .

template specialization is something similar to overriding (but not really) that is based off of pattern matching. If the arguments to the template can be matched by the pattern of a specialization, it is used instead.

This pattern matching does not do type conversion in the same way that function overrides do. SFINAE is in play however, for advanced work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM