简体   繁体   English

检查/修改迭代器“constness”

[英]Check/modify iterator “constness”

I have two and a half closely related questions. 我有两个半密切相关的问题。 Given an STL iterator-type passed as a template parameter: 给定作为模板参数传递的STL迭代器类型:

  1. How to determine whether the type corresponds to a const- or non-const iterator? 如何确定类型是对应于const还是非const迭代器?
  2. Alternatively to 1., how to impose (using enable_if s for instance) that this type corresponds to a non-const iterator? 除了1.之外,如何强制(例如使用enable_if )此类型对应于非const迭代器?
  3. How to obtain the const- version of the iterator from the non-const one (and vice versa )? 如何从非常量中获取迭代器的常量( 反之亦然 )? [ Note: answered in this post ; [注:在这篇文章中回答; not surprisingly, you can't. 不足为奇,你做不到。 ] ]

Where does this question come from: 这个问题来自哪里:

I wrote a small class to facilitate arithmetic/relational/algebraic operations on vectors (by vector I mean 1d fixed-size data, not the STL vectors). 我写了一个小类来促进对向量的算术/关系/代数运算(通过向量我的意思是1d固定大小的数据,而不是STL向量)。 Instead of imposing a specific data container, I've defined an interface and derived several possible containers that are basically "wrapping" various ways of storing data. 我没有强制使用特定的数据容器,而是定义了一个接口并派生了几个可能的容器,它们基本上“包装”了各种存储数据的方式。 One of these containers is a wrapper for STL-iterators, and I'm having some troubles with it. 其中一个容器是STL迭代器的包装器,我遇到了一些麻烦。

Question 1: 问题1:

You could use the following type trait: 您可以使用以下类型特征:

template<typename T, typename = void>
struct is_const_iterator : std::false_type { };

template<typename T>
struct is_const_iterator<T,
    typename std::enable_if<
        std::is_const<
            typename std::remove_pointer<
                typename std::iterator_traits<T>::pointer
                >::type
            >::value
        >::type> : std::true_type { };

Here is a demonstration: 这是一个演示:

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

template<typename T, typename = void>
struct is_const_iterator : std::false_type { };

template<typename T>
struct is_const_iterator<T,
    typename std::enable_if<
        std::is_const<
            typename std::remove_pointer<
                typename std::iterator_traits<T>::pointer
                >::type
            >::value
        >::type> : std::true_type { };

int main()
{
    typedef std::list<int>::iterator LI;
    typedef std::list<int>::const_iterator CLI;
    static_assert(is_const_iterator<LI>::value, "!"); // Fires
    static_assert(is_const_iterator<CLI>::value, "!"); // Does not fire

    typedef std::vector<int>::iterator VI;
    typedef std::vector<int>::const_iterator CVI;
    static_assert(is_const_iterator<VI>::value, "!"); // Fires
    static_assert(is_const_iterator<CVI>::value, "!"); // Does not fire
}

And here is a live example . 这是一个实例

Question 2: 问题2:

With the above type trait, this becomes simple. 使用上述类型特征,这变得简单。 Suppose you have a function template foo() that you want to constrain so that it accepts only non- const iterators: 假设您有一个要约束的函数模板foo() ,以便它只接受非const迭代器:

template<typename It,
    typename std::enable_if<!is_const_iterator<It>::value>::type* = nullptr>
void foo(It i)
{
    // Does something with i...
}

And a simple demonstration program: 还有一个简单的演示程序:

int main()
{
    std::vector<int> v;
    foo(v.begin()); // OK
    foo(v.cbegin()); // ERROR!
}

And here is a live example . 这是一个实例

For 1), you could do something like this: 对于1),你可以做这样的事情:

std::is_const<
  typename std::remove_reference<
    typename std::iterator_traits<Iterator>::reference
  >::type
>::value

Or this: 或这个:

std::is_const<
  typename std::remove_reference<
    decltype(*iterator)
  >::type
>::value

You can use these predicates to pass to std::enable_if to implement 2). 您可以使用这些谓词传递给std::enable_if来实现2)。

NOTE: As pointed out by R. Martinho Fernandes in the comments, these predicates will fail if the iterator in question uses a different type than plain references for its reference trait (such as std::vector<bool>::const_iterator does). 注意:正如R. Martinho Fernandes在评论中所指出的,如果所讨论的迭代器使用与其reference特征的普通引用不同的类型(例如std::vector<bool>::const_iterator ),则这些谓词将失败。

You could use SFINAE on 你可以使用SFINAE

decltype( **(T*)0 = std::move(**(T*)0) )

or (Xeo's preference) 或(Xeo的偏好)

decltype( *declval<T&>() = std::move(*declval<T&>()) )

which checks whether dereferencing the iterator gives you something assignable. 检查是否取消引用迭代器会给你一些可分配的东西。 Not perfect, if the element type of the collection isn't assignable, but then what good would it be to have a non- const_iterator anyway? 如果集合的元素类型不可分配,那么不完美,但是反正有一个非const_iterator会有什么好处呢?

Don't test for const_iterator , test for the operation your algorithm actually needs. 不要测试const_iterator ,测试算法实际需要的操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM