c++ - 基于 : issue with constness 范围内的自定义迭代器

标签 c++ c++11

以下代码基于 Modern C++ programming cookbook 中的代码,并在 VS 2017 中编译:

#include <iostream>

using namespace std;

template <typename T, size_t const Size> 
class dummy_array 
{ 
    T data[Size] = {}; 

public: 
    T const & GetAt(size_t const index) const 
    { 
        if (index < Size) return data[index]; 
        throw std::out_of_range("index out of range"); 
    } 

    // I have added this
    T & GetAt(size_t const index) 
    { 
        if (index < Size) return data[index]; 
        throw std::out_of_range("index out of range"); 
    } 

    void SetAt(size_t const index, T const & value) 
    { 
        if (index < Size) data[index] = value; 
        else throw std::out_of_range("index out of range"); 
    } 

    size_t GetSize() const { return Size; } 
};

template <typename T, typename C, size_t const Size> 
class dummy_array_iterator_type 
{ 
public: 
    dummy_array_iterator_type(C& collection,  
        size_t const index) : 
        index(index), collection(collection) 
    { } 

    bool operator!= (dummy_array_iterator_type const & other) const 
    { 
        return index != other.index; 
    } 

    T const & operator* () const 
    { 
        return collection.GetAt(index); 
    }

    // I have added this
    T & operator* () 
    { 
        return collection.GetAt(index); 
    } 

    dummy_array_iterator_type const & operator++ () 
    { 
        ++index; 
        return *this; 
    } 

private: 
    size_t   index; 
    C&       collection; 
};

template <typename T, size_t const Size> 
using dummy_array_iterator =  dummy_array_iterator_type<T, dummy_array<T, Size>, Size>; 

// I have added the const in 'const dummy_array_iterator_type'
template <typename T, size_t const Size> 
using dummy_array_const_iterator =  const dummy_array_iterator_type<T, dummy_array<T, Size> const, Size>;

template <typename T, size_t const Size> 
inline dummy_array_iterator<T, Size> begin(dummy_array<T, Size>& collection) 
{ 
    return dummy_array_iterator<T, Size>(collection, 0); 
} 

template <typename T, size_t const Size> 
inline dummy_array_iterator<T, Size> end(dummy_array<T, Size>& collection) 
{ 
    return dummy_array_iterator<T, Size>(collection, collection.GetSize()); 
} 

template <typename T, size_t const Size> 
inline dummy_array_const_iterator<T, Size> begin(dummy_array<T, Size> const & collection) 
{ 
    return dummy_array_const_iterator<T, Size>(collection, 0); 
} 

template <typename T, size_t const Size> 
inline dummy_array_const_iterator<T, Size> end(dummy_array<T, Size> const & collection) 
{ 
    return dummy_array_const_iterator<T, Size>(collection, collection.GetSize()); 
}

int main(int nArgc, char** argv)
{
    dummy_array<int, 10> arr;

    for (auto&& e : arr) 
    { 
        std::cout << e << std::endl; 
        e = 100;    // PROBLEM
    } 

    const dummy_array<int, 10> arr2;

    for (auto&& e : arr2)   // ERROR HERE
    { 
        std::cout << e << std::endl; 
    } 
}

现在,错误指向这条线

T & operator* ()

说明

“return”:无法从“const T”转换为“T &””

...这是从我在 arr2 上基于范围的 for 循环中产生的。

为什么编译器选择 operator*() 的非常量版本?。我已经看了很长时间了;我认为这是因为它认为调用此运算符的对象不是常量:这应该是一个 dummy_array_const_iterator。但是,这个对象已经通过

声明为常量
template <typename T, size_t const Size> 
using dummy_array_const_iterator =  const dummy_array_iterator_type<T, dummy_array<T, Size> const, Size>;

...所以我真的不明白发生了什么。有人可以澄清一下吗?

TIA

最佳答案

dummy_array_const_iterator::operator * 应该总是返回 T const & 而不管迭代器对象本身的常量性。

实现这一点的最简单方法可能只是用 T const 声明它作为基础迭代器值类型:

template <typename T, size_t const Size> 
using dummy_array_const_iterator = dummy_array_iterator_type<T const, dummy_array<T, Size> const, Size>;

由于您按值返回迭代器,因此它的常量很容易是 lost通过 C++ 类型推导规则并仅将 dummy_array_const_iterator 声明为 const dummy_array_iterator_type 的别名是不够的。即以下失败:

#include <type_traits>

struct I { };
using C = I const;
C begin();

int bar()
{
    auto x = begin(); // type of x is deduced as I
    static_assert(std::is_same<I, decltype(x)>::value, "same"); // PASS
    static_assert(std::is_same<decltype(begin()), decltype(x)>::value, "same"); // ERROR
}

关于c++ - 基于 : issue with constness 范围内的自定义迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54690996/

相关文章:

linux - 用两个 QGraphicsSimpleTextItem-s 制作一个 QGraphicsItemGroup?

c++ - 编译时错误: Union default constructor is deleted

c++ - 尝试 libssh 身份验证时的核心转储

c++ - Arduino——关于数据类型

c++ - C++ 中的数字反转

C++11 Watchdog 类,测试应用程序不想退出

c++ - 如何将可变参数模板函数声明为友元?

c++ - boost 定时器限制

c++ - Qt HBoxLayout - 将小部件转换到新行

c++ - 模板模板参数简单示例