C++ 将范围传递给C+;时,如何处理迭代器/常量迭代器不匹配+;算法?

C++ 将范围传递给C+;时,如何处理迭代器/常量迭代器不匹配+;算法?,c++,templates,iterator,C++,Templates,Iterator,我正在处理的项目的部分源代码负责压缩一系列“事件”,如下所示: #include <iterator> #include <list> typedef int Event; typedef std::list<Event> EventList; struct Compressor { // Returns an iterator behind the last element which was 'eaten' virtual Event

我正在处理的项目的部分源代码负责压缩一系列“事件”,如下所示:

#include <iterator>
#include <list>

typedef int Event;

typedef std::list<Event> EventList;

struct Compressor {
    // Returns an iterator behind the last element which was 'eaten'
    virtual EventList::const_iterator eatEvents( const EventList &l ) = 0;
};

// Plenty of Compressor subclasses exist

void compressAndCopyEatenEvents( Compressor &c ) {
    EventList e;
    e.push_back( 1 );
    EventList::const_iterator newEnd = c.eatEvents( e );

    EventList eatenEvents;
    std::copy( e.begin(), newEnd, std::back_inserter( eatenEvents ) ); // barfs
}
#包括
#包括
typedef int事件;
typedef std::list EventList;
结构压缩机{
//返回“已吃”的最后一个元素后面的迭代器
虚拟事件列表::常量迭代器事件(常量事件列表&l)=0;
};
//存在大量压缩器子类
空压机和副本(压缩机和c){
事件列表e;
e、 推回(1);
事件列表::const_迭代器newEnd=c.eatEvents(e);
事件列表事件;
std::copy(e.begin(),newEnd,std::back_inserter(eatenvents));//barfs
}
这里的问题是
compressandcopyeatevents
函数有一个非常量事件列表;此列表传递给
eatEvents
方法,该方法引用const并生成
const\u迭代器。现在,
compressAndCopyEatenEvenst
函数想要复制已吃事件的范围,所以它决定使用一些算法(
std::copy
,当然也可以用正确的
std::list
构造函数调用来替换,关键是各种范围都存在这个问题)

不幸的是(?)许多(如果不是全部?)范围需要由相同的迭代器类型组成。但是,在上面的代码中,“e.begin()”生成一个
EventList::iterator
(因为对象不是const),而“newEnd”是一个
EventList::const\u iterator

这里是否有设计缺陷导致了这种混乱?您将如何解决此问题?

考虑使用

EventList::const_iterator b = e.begin();
std::copy( b, newEnd, std::back_inserter( eatenEvents ) );

这将导致调用正确的
list::begin()
重载,并使
std::copy
干净地编译。

在C++03中,唯一可能的方法是强制转换。(这很难看,这是一个设计缺陷,是的)

在C++11中,您有
cbegin
cend
函数(总是返回
const\u迭代器
s),因此您只需

std::copy( e.cbegin(), newEnd, std::back_inserter( eatenEvents ) );

您可以添加第二个EateEvents重载,这样编译器将自动选择正确的重载,以保持常量:

virtual EventList::iterator eatEvents( EventList &l ) = 0;
(它们中的一个或两个可以是非虚拟的,并且可以在单个底层函数中实现。)


有时这很管用,尽管我不相信这是一件完美的事情。

看看大师怎么说:

有效STL中的Scot Meyers

项目26。相对于常量迭代器、反向迭代器和 常量反迭代器。 尽管容器支持四种迭代器类型,但其中一种类型具有其他类型没有的特权。那个类型是迭代器,迭代器是特殊的。

typedef-deque-IntDeque//STL容器和
typedef lntDeque::迭代器Iter;//迭代器类型更容易
typedef lntDeque::常量迭代器conster;//和你一起工作
//使用一些typedef
Iter i;
便秘;
…//使i和ci指向
//同一容器
如果(i==ci)//比较迭代器
//和一个常量迭代器
项目27。使用distance和advance将容器的常量迭代器转换为迭代器。

typedef deque<int> IntDeque; //convenience typedefs
typedef lntDeque::iterator Iter;
typedef lntDeque::const_iterator ConstIter;
ConstIter ci; // ci is a const_iterator
…
Iter i(ci); // error! no implicit conversion from
// const_iterator to iterator
Iter i(const_cast<Iter>(ci)); // still an error! can't cast a
// const_iterator to an iterator
typedef-deque-IntDeque//方便型
类型定义lntDeque::迭代器Iter;
类型定义lntDeque::常量迭代器构造器;
便秘ci;//ci是常量迭代器
…
Iter i(ci);//错误!没有从的隐式转换
//常量迭代器到迭代器
国际热核实验堆一期(const_cast(ci));//还是个错误!不能投
//常量迭代器到迭代器
有效的是前进和距离

typedef deque<int> IntDeque; //as before
typedef IntDeque::iterator Iter;
typedef IntDeque::const_iterator ConstIter;
IntDeque d;
ConstIter ci;
… // make ci point into d
Iter i(d.begin()); // initialize i to d.begin()
Advance(i, distance(i, ci)) //move i up to where ci is
// (but see below for why this must
// be tweaked before it will compile)
typedef-deque-IntDeque//一如既往
typedef IntDeque::迭代器Iter;
typedef IntDeque::const_迭代器;
IntDeque d;
便秘;
…//使ci指向d
Iter i(d.begin());//初始化i到d。开始()
前进(i,距离(i,ci))//将i移到ci所在的位置
//(但为什么必须这样做,请参见下文。)
//在编译之前进行调整)

您需要非常量迭代器吗?如果没有,那么您应该让所有代码只使用常量迭代器而传递这些信息太多了?由于你的消费方式,我找不到解决的办法…+1提到有效的STL-我在家里有,但我没有想到咨询它。我会仔细阅读的!总是喜欢STL!!因为算法远比手写循环有效!!您可以将
e
分配给
常量事件列表&
对象,该对象将自动生成所需的
常量迭代器
typedef deque<int> IntDeque; //STL container and
typedef lntDeque::iterator Iter; // iterator types are easier
typedef lntDeque::const_iterator ConstIter; // to work with if you
// use some typedefs
Iter i;
ConstIter ci;
… //make i and ci point into
// the same container
if (i == ci ) ... //compare an iterator
// and a const_iterator
typedef deque<int> IntDeque; //convenience typedefs
typedef lntDeque::iterator Iter;
typedef lntDeque::const_iterator ConstIter;
ConstIter ci; // ci is a const_iterator
…
Iter i(ci); // error! no implicit conversion from
// const_iterator to iterator
Iter i(const_cast<Iter>(ci)); // still an error! can't cast a
// const_iterator to an iterator
typedef deque<int> IntDeque; //as before
typedef IntDeque::iterator Iter;
typedef IntDeque::const_iterator ConstIter;
IntDeque d;
ConstIter ci;
… // make ci point into d
Iter i(d.begin()); // initialize i to d.begin()
Advance(i, distance(i, ci)) //move i up to where ci is
// (but see below for why this must
// be tweaked before it will compile)