Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何习惯性地编写常量迭代器?_C++_Templates - Fatal编程技术网

C++ 如何习惯性地编写常量迭代器?

C++ 如何习惯性地编写常量迭代器?,c++,templates,C++,Templates,我正在编写一个链表实现,但我一直在研究如何实现一个常量迭代器,该迭代器是通过cbegin()与普通迭代器一起访问的。以下是我尝试的解决方案: #include <iostream> using namespace std; template <typename T> class ListNode { public: ListNode<T>* next_; ListNode<T>* prev_; T data_;

我正在编写一个链表实现,但我一直在研究如何实现一个常量迭代器,该迭代器是通过
cbegin()
与普通迭代器一起访问的。以下是我尝试的解决方案:

#include <iostream>

using namespace std;

template <typename T>
class ListNode {
public:
    ListNode<T>* next_;
    ListNode<T>* prev_;
    T data_;

    ListNode():
        next_(nullptr),
        prev_(nullptr)
    {}
};

template <typename T>
class ListIterator
{
    typedef ListNode<T> node;
    typedef ListNode<T>* pointer;
    pointer p_;

public:
    ListIterator(pointer p) : p_(p) {}
    T& operator*() { return p_->data_; }
};

template<typename T>
class List
{
public:
    typedef ListNode<T> node;
    typedef ListNode<T>* pointer;
    typedef ListIterator<T> iterator;
    typedef ListIterator<const T> constIterator;

    List() :
        head_(nullptr),
        tail_(nullptr),
        size_(0)
    {}

    void pushBack(pointer p) {
        p->next_ = nullptr;
        p->prev_ = nullptr;

        if (size_ == 0) {
            head_ = p;
        } else {
            tail_->next_ = p;
            p->prev_ = tail_;
        }

        tail_ = p;
        ++size_;
    }

    iterator begin() { return head_; }
    iterator end() { return nullptr; }
    constIterator cbegin() { return head_; }
    constIterator cend() { return nullptr; }

private:
    pointer head_;
    pointer tail_;
    unsigned int size_;
};

class Dog {
public:
    int age;
};

int main() {
    auto list = List<Dog>();
    auto dogNode = ListNode<Dog>();
    list.pushBack(&dogNode);
    auto b = list.cbegin();
}
#包括
使用名称空间std;
样板
类ListNode{
公众:
ListNode*next;
ListNode*上一个;
T数据;
ListNode():
下一步(nullptr),
上一页(空页)
{}
};
样板
类列表迭代器
{
typedef列表节点;
typedef ListNode*指针;
指针p_;
公众:
ListIterator(指针p):p_Up(p){}
T运算符*(){return p->data}
};
样板
班级名单
{
公众:
typedef列表节点;
typedef ListNode*指针;
typedef列表迭代器迭代器;
typedef列表迭代器;
列表():
头部(空侧),
尾翼(空侧),
尺寸(0)
{}
无效回推(指针p){
p->next_u2;=空PTR;
p->prev_uu=nullptr;
如果(大小=0){
头=p;
}否则{
尾部->下一个->下一个=p;
p->prev=tail;
}
尾部=p;
++大小;
}
迭代器begin(){return head;}
迭代器end(){return nullptr;}
构造函数cbegin(){返回头}
构造函数cend(){return nullptr;}
私人:
指针头;
指针尾;
无符号整数大小;
};
班犬{
公众:
智力年龄;
};
int main(){
自动列表=列表();
自动dogNode=ListNode();
列表。回推(&dogNode);
auto b=list.cbegin();
}
当我尝试运行这个时,我得到了错误
错误:无法将“List::pointer”(又名“ListNode*)类型的返回值转换为函数返回类型
'List::constIterator'(又名'ListIterator')

这个错误对我来说是有意义的,但我无法找到一个不涉及编写单独的
ConstListIterator
类的好的解决方法(这是可行的,但从
ListIterator
复制所有运算符重载代码感觉是错误的——本示例中省略了大部分内容)

在中,作者使用了将
ListIterator
TNode
参数化的方法,在这种情况下,它将是
ListNode
而不是
Dog
。这种方法的问题是,
操作符*
不能返回实际的
Dog
,因为
列表迭代器
类不知道typename
Dog
。因此,该解决方案只是在
数据类型中硬编码,因此您失去了元编程的所有好处

是否有一个技巧可以让它很好地工作,或者我应该只使用一个单独的
ConstListIterator


谢谢大家!

出现错误的原因是您试图从返回类型为
conditerator
的函数返回类型为
ListNode*
head

为了回答您的问题,
迭代器
常量迭代器
之间的唯一区别是
常量迭代器
返回容器的
值类型
的常量引用,而不仅仅是引用。因此,将
const T
作为模板参数传递应该会产生所需的功能。由于
运算符*
返回
T&
,如果
T
改为
const T
,则返回
const T&
,这是正确的。您遇到的问题似乎是因为您从
迭代器
函数返回了错误的类型,如上所述

您的迭代器函数应该如下所示:

iterator begin() { return iterator{head_}; }
iterator end() { return iterator{nullptr}; }
constIterator cbegin() { return constIterator{head_}; }
constIterator cend() { return constIterator{nullptr}; }
这将返回使用指针
head
nullptr
构造的
iterator
conditerator
对象,这正是您想要的


用于迭代器的模板参数(列表的
值类型
)是正确的。

将节点类型作为迭代器的模板参数是合理的,并且允许

using constIterator=ListIterator<const ListNode<T>>;
*p
的常数传递到
数据,然后传递到返回类型

在C++14之前 在C++11中,可以为
ListNode
配备

using value_type=T;
并使用类型特征,如
is_const
conditional
const ListNode
派生
const T


在C++03中,您可以直接为此编写基于SFINAE的trait。

编辑以反映该事实。再次编辑。谢谢
using value_type=T;