How to restrict an iterator to being a forward iterator?

后端 未结 4 2021
终归单人心
终归单人心 2021-02-09 16:38

I have a function that needs to enumerate an iterator multiple times, but according to MSDN, \"Once you increment any copy of an input iterator, none of the other copies can

相关标签:
4条回答
  • 2021-02-09 16:46

    You can use SFINAE and replace bool by:

    typename enable_if<
       is_same<typename std::iterator_traits<It>::iterator_category,
               std::forward_iterator_tag>::value,
       bool>::type
    

    You may need to define is_same and enable_if yourself if you don't want to pull them from Boost or TR1:

    template <typename A, typename B>
    struct is_same { static const bool value = false; };
    
    template <typename T>
    struct is_same<T, T> { static const bool value = true; };
    
    template <bool, typename> struct enable_if { };
    template <typename T> struct enable_if<true, T> { typedef T type; };
    
    0 讨论(0)
  • 2021-02-09 16:51

    Not tested but you could try something along the lines of:

    template<typename It, typename TCallback /*signature: bool(value_type)*/>
    bool EnumerateTwice_Interal(const It &begin, const It &end, TCallback callback, 
          std::forward_iterator_tag)
    {
         //do your things
    }
    
    template<typename It, typename TCallback /*signature: bool(value_type)*/>
    bool EnumerateTwice(const It &begin, const It &end, TCallback callback)
    {
        EnumerateTwice_Internal(begin, end, callback,
            typename std::iterator_traits<It>::iterator_category());
    }
    
    0 讨论(0)
  • 2021-02-09 17:06

    You can do this using std::enable_if:

    #include <iterator>
    #include <type_traits>
    #include <utility>
    
    template <typename It, typename TCallback>
    typename std::enable_if<std::is_base_of<std::forward_iterator_tag,
                            typename std::iterator_traits<It>::iterator_category>::value,
                        bool>::type
    EnumerateTwice(It begin, It end, TCallback) {
        ...
    }
    

    This uses class from C++11 but all of this can be done in C++03 as well.

    0 讨论(0)
  • 2021-02-09 17:08

    To expand on rodrigo's answer -- I found this solution, and thought it's worth mentioning:

    struct True { unsigned char _[2]; operator bool() const { return true; } };
    char is_forward_iterator(std::input_iterator_tag const *) { return 0; }
    True is_forward_iterator(std::forward_iterator_tag const *) { return True(); }
    

    Now, if you want to check it inside some function, you can say:

    if (is_forward_iterator(static_cast<iterator_traits<It>::iterator_category*>(0)))
    {
        ...
    }
    

    and if you want to check it within templates, you can check for:

    sizeof(
      is_forward_iterator(static_cast<iterator_traits<It>::iterator_category*>(0))
    ) > 1
    

    with the primary advantage of this method being that it avoids declaring templates (e.g. for better compilation speed).

    0 讨论(0)
提交回复
热议问题