0

I am getting an error when trying to add std::iterator_traits for a templated member struct - i.e. I have an iterator class which is a member of a templated outer class:

namespace Toolbox {
    template <typename CharType>
    class substring_container_adapter
    {
    public:
        struct iterator // : public std::iterator<std::forward_iterator_tag, const CharType *>   C++ 17 is very upset at this approach!
        {
            // iterator constructor
            iterator(const CharType * pszPosition, const CharType * pszDelimeters)

Later, I try to add a partial specialization for iterator traits to std because apparently inheriting from std::iterator is deprecated (even though that - or boost::iterator_adaptor<> makes perfect sense and actually works in this and other contexts)...

// define iterator traits for our custom iterators
namespace std 
{
    template <typename CharType>
    struct iterator_traits<class Toolbox::substring_container_adapter<CharType>::iterator>
    {
        using iterator_category = forward_iterator_tag;
        using value_type = CharType;
    };
}

However, VC++ 2017 version 15.7.3 (C++ 17 enabled for this project) complains:

error C2764: 'CharType': template parameter not used or deducible in partial specialization 'std::iterator_traits::iterator>'

Why not?

I suspect that this is !@#$ annoying limitation due to trying to partially specialize a member struct instead of a templated struct outside of substring_container_adapter<>?

Mordachai
  • 9,412
  • 6
  • 60
  • 112
  • [partial specialization](https://en.cppreference.com/w/cpp/language/partial_specialization) I think you've just miss added `class` keyword into `struct iterator_traits – Victor Gubin Jun 06 '18 at 14:59
  • And you don't need those partial template specialization at all :) since [ForwardIterator](https://en.cppreference.com/w/cpp/concept/ForwardIterator) – Victor Gubin Jun 06 '18 at 15:02
  • FWIW - adding more `typename` specifiers doesn't change things (in VS 2017) - same error results. Seems like it is basic lack of language that it cannot handle this construct of partial spec for an inner class of a template (but I'm hoping someone can clarify this here) – Mordachai Jun 06 '18 at 15:12
  • @VictorGubin I don't see how that helps (yet) - since Concepts are *still* not a part of the language. – Mordachai Jun 06 '18 at 15:12
  • Note that you need all 5 aliases to be a proper `std::iterator_traits`, so you don't gain anything there. – Caleth Jun 06 '18 at 15:23

1 Answers1

2

The correct thing to do here is to put the type aliases in iterator, rather than try to partially specialize std::iterator_traits.

namespace Toolbox {
    template <typename CharType>
    class substring_container_adapter
    {
    public:
        struct iterator // : public std::iterator<std::forward_iterator_tag, const CharType *>   C++ 17 is very upset at this approach!
        {
            using iterator_category = forward_iterator_tag;
            using value_type = const CharType *;
            using reference = const CharType * &;
            using pointer = const CharType * *;
            using difference_type = std::ptrdiff_t;

            // iterator constructor
            iterator(value_type pszPosition, value_type pszDelimeters)

            // ...
        }
    }
}

A main reason for deprecating std::iterator is that the committee disliked the impression that it gave, that all Iterators should derive from it, as none of the container iterators are required to. You can define an exact replacement

namespace not_std {
  template<class Category, class T, class Distance = ptrdiff_t,
           class Pointer = T*, class Reference = T&>
  struct iterator {
    using iterator_category = Category;
    using value_type        = T;
    using difference_type   = Distance;
    using pointer           = Pointer;
    using reference         = Reference;
  };
}
Caleth
  • 52,200
  • 2
  • 44
  • 75
  • That looks entirely reasonable. But why is this preferred (beyond "it works!" ;) I really want to declare that my iterator class is a type of iterator, rather than having to specify things piecemeal (just feels wrong or arbitrary) – Mordachai Jun 06 '18 at 15:10
  • The above, by the way, is effectively what I get if I inherit from `boost::iterator_adaptor<>` which I was doing previously due to the above limitations and no analog in `std` – Mordachai Jun 06 '18 at 15:14
  • 1
    have a look at [this question](https://stackoverflow.com/questions/43268146/why-is-stditerator-deprecated) – Caleth Jun 06 '18 at 15:14
  • Thanks. That's their reasoning - and I just personally think it kind of sucks. Just as my previous comment - it's just this arbitrary set of using declarations with no rhyme nor reason (except in the minutia we all have to tuck away on behalf of c++ and the standard bodies idiosyncrasies - blech!) Not dissing you - and I appreciate the clarity of knowing "why" - but I'll state for the record "that's dumb" (purely IMO). ;) – Mordachai Jun 06 '18 at 15:18
  • 1
    This is a perfectly fine work-around. I'll probably mark it as the answer. But I'm hoping someone will clarify what limitation exists in c++17 that makes it impossible to do the partial specialization for std::iterator_traits for an inner type of a template. – Mordachai Jun 06 '18 at 15:20
  • When I attempt to actually use your suggested solution, I still get compiler errors (in debug) : `xutility(1120): error C2938: '_Iter_cat_t::iterator>' : Failed to specialize alias template` --- I'm guessing that the fact that this is an embedded type flummoxed the traits partial specialization and failed to resolve to the public `using iterator_category` I 2x the spelling! – Mordachai Jun 06 '18 at 17:08