检查模板参数是否为std::vector<T>::iterator。

7

如何检查模板参数是否为std::vector<T>::iterator

对于void类型,我们有std::is_void。是否有类似于std::vector<T>::iterator的东西?


我不相信你可以这样做,但是你可以检查参数是否为随机访问迭代器。 - aschepler
4
我认为模板的整个意义就是不具体化。如果需要针对特定类型进行特殊实现,可以使用模板特化。 - user2717954
1
大致上你可以将其视为 VecIt,然后验证 typename std::vector<typename std::iterator_traits<VecIt>::value_type>::iteratorVecIt 是否命名为相同的类型,但这并不能保证你得到的东西实际上是一个指向向量的迭代器,因此它并不是那么有用。 - T.C.
3
你实际上想解决的问题是什么? - Barry
1
标准允许std::vector<T>::iteratorT*。这可能会给你设计的任何测试带来很多误报。 - Bo Persson
显示剩余3条评论
4个回答

7
您可以创建一个 trait 来实现这一点:
#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");
}

【实时演示】


对于is_vector_iterator<std::list<int>::iterator>,返回true。 - aschepler
对于 std::vector<bool>::iterator 失败 ;) - Quentin
@W.F. 为什么你要使用 std::decay_t<decltype(*std::declval<T>())> 而不是直接使用 T::value_type - Come Raczy
据我所知,向量迭代器是与实现相关的,因此它不必包含 value_type(正如 Bo Persson 建议的那样,甚至允许将其定义为指向所包含类型的指针)... - W.F.

4

另一种解决方案也使用了 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


不幸的是,这也适用于 std::list<int>::iterator。目的是确定它是否为 std::vector<T>::iterator。不仅仅是一个迭代器。 - O'Neil
我现在修好了! - Pedro Boechat
你认为:演示 - O'Neil
我想我终于修好了。我肯定学到了一些东西...而且我的例子现在和你的相当相似。 - Pedro Boechat
我不知道std :: iterator_traits为原始指针提供了专门的特化! - Pedro Boechat

3
我认为最好使用std::iterator_traits
#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


为什么要使用 std::iterator_traits<It>::value_type 而不是 It::value_type - Come Raczy
1
因为正如Bo Persson所说:“标准允许std::vector<T>::iteratorT*”,而指针没有value_type成员。 - O'Neil
@ComeRaczy 此外,要处理bool的情况,其中*std :: declval <It>()不是bool&而是代理。 - O'Neil

2
你可以为此编写一个 trait :
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)) {};

在这里,我获取了 *t 的衰变类型,以创建 vector<type>::iterator 并检查其是否与 T 相等。它可以正常工作,但是对于 vector<bool> 并不适用,因为它本质上并不是一个向量。

演示


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接