【问题标题】:Check if a template argument is a std::vector<T>::iterator检查模板参数是否为 std::vector<T>::iterator
【发布时间】:2017-03-23 14:00:33
【问题描述】:

如何检查模板参数是否为std::vector&lt;T&gt;::iterator

对于 void 类型,我们有 std::is_void。 std::vector&lt;T&gt;::iterator 有类似的东西吗?

【问题讨论】:

  • @W.F. &lt;T&gt; 在我添加之前没有出现。对此感到抱歉。我正在考虑编写自定义特征。喜欢template &lt;template &lt;typename T&gt; std::vector&lt;T&gt; class&gt; struct is_vec_iterator { static const bool value = true; };
  • 我认为模板的全部意义在于不具体。如果您需要特定类型的特殊实现,请使用模板专业化
  • 大概你可以把它当作VecIt 然后验证typename std::vector&lt;typename std::iterator_traits&lt;VecIt&gt;::value_type&gt;::iteratorVecIt 命名相同的类型,但这并不能保证你得到的东西实际上是一个迭代器向量,所以没那么有用。
  • 你真正想要解决的问题是什么?
  • 标准允许std::vector&lt;T&gt;::iteratorT*。这可能会给您设计的任何测试带来很多误报。

标签: c++ templates vector iterator


【解决方案1】:

你可以为此创建一个特征:

#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]

【讨论】:

  • is_vector_iterator&lt;std::list&lt;int&gt;::iterator&gt; 为真。
  • std::vector&lt;bool&gt;::iterator 失败;)
  • @W.F.你为什么使用std::decay_t&lt;decltype(*std::declval&lt;T&gt;())&gt; 而不仅仅是T::value_type
  • @ComeRaczy 据我所知,向量迭代器依赖于实现,因此它不必包含 value_type (正如 Bo Persson 建议的那样,甚至允许将它定义为指向包含的指针类型)...
【解决方案2】:

你可以为此写一个特征:

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&lt;type&gt;::iterator 并检查它是否与 T 相等。它适用于 vector&lt;bool&gt; 的例外,它不是真正的向量。

demo

【讨论】:

    【解决方案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&lt;It&gt;::value_type 而不是It::value_type
    • 因为正如上面 Bo Persson 所说:标准允许 std::vector&lt;T&gt;::iteratorT* 并且指针没有 @ 987654328@会员。
    • @ComeRaczy 另外,使用bool 处理这种情况,其中*std::declval&lt;It&gt;() 不是bool&amp;,而是代理。
    【解决方案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&lt;int&gt;::iterator 也是如此。目的是确定它是否为std::vector&lt;T&gt;::iterator。不仅仅是一个迭代器。
    • 我现在修好了!
    • 所以你认为:demo
    • 我想我现在终于修好了。我确实学到了一些东西......无论如何,我的例子现在和你的很相似。
    • 我不知道 std::iterator_traits 有专门的原始指针!
    猜你喜欢
    • 2013-05-31
    • 2014-01-22
    • 2011-04-13
    • 2022-11-21
    • 2016-11-26
    • 2013-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多