基于以下范围的自定义迭代器:常量问题

时间:2019-02-14 12:58:29

标签: 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&'“

...这是我在for上基于arr2的范围循环中引发的。

为什么编译器选择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

2 个答案:

答案 0 :(得分:1)

我找到了一种仅在T& operator*()不恒定的情况下启用C的方法:

    template <class Tp = T>
    typename std::enable_if<std::is_const<C>::value, Tp>::type const& operator* () const 
    { 
        return collection.GetAt(index); 
    }

    template <class Tp = T>
    typename std::enable_if<!std::is_const<C>::value, Tp>::type & operator* () const 
    { 
        return collection.GetAt(index); 
    }

我不知道语法(我从https://stackoverflow.com/a/26678178获得)

答案 1 :(得分:1)

public function all_users(){ $this->db->select('users.*, user_profile.column1 as column1, user_profile.column2 as column2'); $this->db->join('user_profile', 'user_profile.user_id = users.user_id', 'left'); $query = $this->db->get('users'); return $query->result_array(); } 应该始终返回dummy_array_const_iterator::operator *,无论迭代器对象本身的常量性如何。

最简单的方法可能就是用T const &声明它为基础迭代器值类型:

T const

由于您要通过值返回迭代器,因此可以通过c ++类型推导规则轻松lost,并且仅将template <typename T, size_t const Size> using dummy_array_const_iterator = dummy_array_iterator_type<T const, dummy_array<T, Size> const, Size>; 声明为dummy_array_const_iterator的别名是不够的。即以下失败:

const dummy_array_iterator_type