【问题标题】:how to detect if a type is an iterator or const_iterator如何检测类型是迭代器还是 const_iterator
【发布时间】:2011-07-22 08:22:42
【问题描述】:

我想知道,是否有办法在编译时检查某个迭代器类型的类型 T 是否为 const_iterator。迭代器定义的类型(value_type,指针,...)在迭代器和 const 迭代器之间是否存在一些差异?

我想实现这样的目标:

typedef std::vector<int> T;

is_const_iterator<T::iterator>::value       // is false
is_const_iterator<T::const_iterator>::value // is true

【问题讨论】:

    标签: c++ templates stl iterator metaprogramming


    【解决方案1】:

    至少在 gcc 上有效的一种方法是通过 reference typedef:

    struct true_type { };
    struct false_type { };
    
    template<typename T>
    struct is_const_reference
    {
        typedef false_type type;
    };
    
    template<typename T>
    struct is_const_reference<T const &>
    {
        typedef true_type type;
    };
    
    template<typename T>
    struct is_const_iterator
    {
        typedef typename is_const_reference<
            typename std::iterator_traits<T>::reference>::type type;
    };
    

    您可以通过使用验证它是否有效

    inline bool test_internal(true_type)
    {
        return true;
    }
    
    inline bool test_internal(false_type)
    {
        return false;
    }
    
    template<typename T>
    bool test(T const &)
    {
        return test_internal(typename is_const_iterator<T>::type());
    }
    
    bool this_should_return_false(void)
    {
        std::list<int> l;
        return test(l.begin());
    }
    
    bool this_should_return_true(void)
    {
        std::list<int> const l;
        return test(l.begin());
    }
    

    在足够高的优化级别下,最后两个函数应该分别减少到return false;return true;。至少他们为我做了。

    【讨论】:

    • 你测试了吗? iterator 类型是否有 reference 类型?将工作代码发布到 ideone!
    • 是的,我查看了反汇编程序的输出,发现测试函数确实返回了所需的结果,作为一个常数。我这里用类型来表示真假,原则上你也可以使用staticconst成员,达到同样的效果。
    • 我指的是这个语法typename T::reference。当l.begin() 的类型可以是iteratorconst_iterator(在您的语法中实际上是T)时,您如何编写此代码。所以我的问题是:iterator::reference 如何工作?你测试过吗?请在 www.ideone.com 上发布工作代码。
    • 我承认在这里很懒——typename std::iterator_traits&lt;T&gt;::reference 会更正确。对于非特殊情况,这是一个指向 typename T::reference 的 typedef,这似乎是迭代器类型的约定。
    • 我添加了std::iterator_traits的使用并上传了结果here
    【解决方案2】:

    这有点 hacky,因为您必须自己传递 T 但它可以工作(模板专业化,g++ 4.4.5):

    template<typename T, typename S>
    struct is_const_iterator {
        enum {
            value = false
        };
    };
    
    template<typename T>
    struct is_const_iterator<T, typename T::const_iterator> {
        enum {
            value = true
        };
    };
    

    这样使用:

    typedef std::vector<int> T;
    is_const_iterator<T, T::iterator>::value           //is false
    is_const_iterator<T, T::const_iterator>::value     //is true
    

    【讨论】:

    • 它还要求您传递容器类型。所以在我看来,这不是一个解决方案!
    【解决方案3】:

    C++03 解决方案:

    由于没有一个答案似乎正确,这是我与 GCC 合作的尝试:

    template<typename T>
    struct is_const_pointer { static const bool value = false; };
    
    template<typename T>
    struct is_const_pointer<const T*> { static const bool value = true; };
    
    template <typename TIterator>
    struct is_const_iterator
    {
        typedef typename std::iterator_traits<TIterator>::pointer pointer;
        static const bool value = is_const_pointer<pointer>::value;
    };
    

    例子:

    int main()
    {
        typedef std::vector<int>::iterator it_type;
        typedef std::vector<int>::const_iterator const_it_type;
    
        std::cout << (is_const_iterator<it_type>::value) << std::endl;
        std::cout << (is_const_iterator<const_it_type>::value) << std::endl;
    }
    

    输出:

    0
    1
    

    在线演示:http://ideone.com/TFYcW

    【讨论】:

    • 是我一个人还是最近缺乏社区支持? :( +1 你说它的工作,它看起来不错
    • 我选择了您的答案,因为您的解决方案使用 std::iterator_traits 类
    • std::iterator_traits&lt;I&gt;::pointer 是代理类类型时不起作用。但是,如果有针对这种情况的解决方案,则必须使用一些非常讨厌的 SFINAE。
    • 这就是我使用reference 的原因,它可以保证不是代理。不过iterator_traits 很好。
    • @SimonRichter reference 是一个代理,例如std::vector&lt;bool&gt; 和其他“类似容器”的东西。
    【解决方案4】:

    在 C++11 中,新的标准头 &lt;type_traits&gt; 提供了 std::is_const&lt;T&gt;, 所以可以简化 Nawaz 的解决方案:

    template<typename Iterator>
    struct is_const_iterator
    {
        typedef typename std::iterator_traits<Iterator>::pointer pointer; 
        static const bool value = 
            std::is_const<typename std::remove_pointer<pointer>::type>::value;
    };
    

    【讨论】:

      【解决方案5】:

      C++11

      template<class IT, class T=decltype(*std::declval<IT>())>    
      constexpr bool  
      is_const_iterator() {   
              return  ! std::is_assignable <
                      decltype( *std::declval<IT>() ),
                      T   
              >::value;
      }
      

      【讨论】:

      • 这触及了 const_iterator 的 constness 的核心——你不能分配给从取消引用迭代器返回的东西。这可能是唯一适用于像 vector 这样古怪的答案。 (当然,它不检查它是否是一个迭代器,或者是可解引用的,但是 OP 假设它是某种迭代器。但是要称它为“is_const_iterator”,它可能应该同时检查 const-ness 和迭代器...)
      • 如果迭代器表示的类型 T 删除了它的赋值运算符,我认为这将无法正常工作。
      猜你喜欢
      • 2018-05-16
      • 2012-08-15
      • 1970-01-01
      • 2011-12-07
      • 2016-05-26
      • 1970-01-01
      • 1970-01-01
      • 2020-08-30
      • 1970-01-01
      相关资源
      最近更新 更多