Check if a template argument is a std::vector<T>::iterator [duplicate]
Asked Answered
K

5

8

How to check if a template argument is a std::vector<T>::iterator?

For void type, we have std::is_void. Is there something like that for std::vector<T>::iterator?

Kandacekandahar answered 9/11, 2016 at 17:7 Comment(8)
@W.F. The <T> didn't show up before I add . Sorry for that. I was thinking about writing custom traits. Like template <template <typename T> std::vector<T> class> struct is_vec_iterator { static const bool value = true; };Kandacekandahar
I don't believe you can, but you can check if the argument is a Random Access Iterator.Fremantle
i think the whole point of templates is to not get specific. use template specialization if you need special implementation for a specific typeMoua
@dotdotdot which standard of C++ are you aiming for?Olenta
@Olenta C++11 or C++14.Kandacekandahar
Roughly you can take it as VecIt and then verify that typename std::vector<typename std::iterator_traits<VecIt>::value_type>::iterator and VecIt name the same type, but that doesn't guarantee that the thing you got is actually an iterator into a vector, so it's not that useful.Popery
What's the problem you're actually trying to solve?Emasculate
The standard allows for std::vector<T>::iterator to be T*. That could give you lots of false positives for any tests you design.Mirabel
S
7

You could create a trait for that:

#include <vector>
#include <list>
#include <type_traits>


template <class T, class = void>
struct is_vector_iterator: std::is_same<T, std::vector<bool>::iterator> { };

template <class T>
struct is_vector_iterator<T, decltype(*std::declval<T>(), std::enable_if_t<!std::is_same<T, std::vector<bool>::iterator>::value>())>: std::is_same<T, typename std::vector<std::decay_t<decltype(*std::declval<T>())>>::iterator> { };

int main() {
    static_assert(is_vector_iterator<std::vector<int>::iterator>::value, "Is not a vector iterator");
    static_assert(is_vector_iterator<std::vector<bool>::iterator>::value, "Is not a vector iterator");
    static_assert(!is_vector_iterator<std::list<int>::iterator>::value, "Is a vector iterator");
    static_assert(!is_vector_iterator<std::list<int>::iterator>::value, "Is a vector iterator");
}

[live demo]

Sinuosity answered 9/11, 2016 at 17:11 Comment(4)
Gives true for is_vector_iterator<std::list<int>::iterator>.Fremantle
Fails for std::vector<bool>::iterator ;)Utilitarian
@Sinuosity why are you using std::decay_t<decltype(*std::declval<T>())> instead of just T::value_type?Biocellate
@ComeRaczy as far as I know vector iterator is implementation dependent and as such it does not have to contain value_type included (as Bo Persson suggested it is even allowed it to be defined as pointer to contained type)...Sinuosity
D
4

An alternative solution also using std::iterator_traits:

#include <iostream>
#include <vector>
#include <list>

template <typename T>
struct is_vector_iterator 
{
    typedef char yes[1];
    typedef char no[2];

    template <typename C>
    static yes& test(
        typename std::enable_if<
            std::is_same<T, typename std::vector<typename C::value_type>::iterator>::value
        >::type*);

    template <typename>
    static no& test(...);

    static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);

};

int main() {
    std::cout << is_vector_iterator<int>::value << std::endl;
    std::cout << is_vector_iterator<int*>::value << std::endl;
    std::cout << is_vector_iterator<std::list<int>::iterator>::value << std::endl;
    std::cout << is_vector_iterator<std::vector<int>::iterator>::value << std::endl;
    return 0;
}

live demo

Dilks answered 9/11, 2016 at 20:4 Comment(5)
Unfortunately, it will also be true for std::list<int>::iterator. The purpose is to determine if it's a std::vector<T>::iterator or not. Not just an iterator.Ender
I fixed it now!Dilks
So you think: demoEnder
I guess I finally fixed it now. I definitely learned something... and my example is quite similar to yours now anyway.Dilks
I didn't know that std::iterator_traits had a specialization for raw pointers!Dilks
P
3

Better using std::iterator_traits I think:

#include <list>
#include <vector>
#include <iterator>

template <class It, class = void>
struct is_vector_iterator : std::false_type { };

template <class It>
struct is_vector_iterator<It, std::enable_if_t<
                                  std::is_same<
                                      It,
                                      typename std::vector< 
                                          typename std::iterator_traits<It>::value_type
                                      >::iterator
                                  >::value
                         >> : std::true_type { };

int main() {
    static_assert(is_vector_iterator<std::vector<int>::iterator>::value, "Is not a vector iterator");
    static_assert(is_vector_iterator<std::vector<bool>::iterator>::value, "Is not a vector iterator");
    static_assert(!is_vector_iterator<std::list<int>::iterator>::value, "Is a vector iterator");
}

DEMO

Pileup answered 9/11, 2016 at 18:17 Comment(3)
why use std::iterator_traits<It>::value_type instead of It::value_type?Biocellate
Because as said Bo Persson above: The standard allows for std::vector<T>::iterator to be T* and a pointer doesn't have a value_type member.Ender
@ComeRaczy Also, to handle the case with bool where *std::declval<It>() is not a bool& but a proxy.Ender
O
2

You can write a trait for this:

namespace detail
{

template<typename T> constexpr std::false_type is_vector_iterator(T&&, ...)
{
    return {};
}

template<typename T>
constexpr auto is_vector_iterator(T&& t, void* = nullptr) ->
decltype(std::is_same<typename std::vector<std::decay_t<decltype(*t)>>::iterator, std::decay_t<T>>{})
{
    return {};
}

}

template<typename T>
struct is_vector_iterator : decltype(detail::is_vector_iterator(declval<T>(), 0)) {};

Here I'm getting the decayed type of *t to make vector<type>::iterator and check that for equality with T. It works with the exception of vector<bool> which isn't really a vector anyway.

demo

Olenta answered 9/11, 2016 at 17:39 Comment(0)
D
-1

It is possible to implement a custom type trait, is_vector_iterator, which evaluates to true if the type T is the same as std::vector<U>::iterator.

The basic idea is to create a helper type trait that accepts two different types as template parameters. It is partial-specialized for the case in which the second argument is the same as std::vector <U>::iterator, where the type U is the value_type of the iterator. Thus, the helper is specialized for only the type T. If the above type is not a std::vector container iterator, the first class is selected; otherwise, the second one is selected.

Example:

namespace detail {
    template <typename, typename>
    struct is_vector_iterator
     : std::false_type {};
    
    template <typename T>
    struct is_vector_iterator<T, typename std::vector<typename std::iterator_traits<T>::value_type>::iterator>
     : std::true_type {};
}

template <typename T>
struct is_vector_iterator
 : detail::is_vector_iterator<T, T> {};

template <typename T>
inline constexpr bool is_vector_iterator_v = is_vector_iterator<T>::value;
Dumah answered 6/7, 2024 at 9:57 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.