最近在写代码的时候遇到这样一个功能需求:在一个类里面使用了一个容器,现在希望将里面的数据用只读方式暴露给外部来读取。这个功能当然很好实现,只需要在这个类里面实现公有的begin()/end()方法,实现时直接调用容器的begin()/end()函数即可。可是过了不一会,新的问题冒出来了:因为我突然发现容器里面的数据是原始数据,还需要对每个数据作一次变换才能使用,而我一方面需要保留这些原始数据,又不想另开缓冲区来存储变换后的数据,那么就只能在访问的同时变换数据。那么,需要解决的技术难题就是:如何能在使用迭代器访问的同时透明的对数据内容进行一次变换?
请看下面的代码,这里我将问题简化为以下的类:
程序代码
class DataSource
{
typedef ::std::vector<FLOAT> StorageType;
typedef StorageType::const_iterator const_iterator;
StorageType data_;
public:
const_iterator begin() const
{
return data_.begin();
}
const_iterator end() const
{
return data_.end();
}
// 其他省略
};
// 以下为调用代码,source是DataSource的一个实例
DataSource::const_iterator first = source.begin();
foo(*first); // 此时我想临时变换source.data_中的数据怎么办?
在容器本身上动手术并不明智,因为我的最终目的是要让这个DataSource能够“侦听”到数据访问的“消息”并在其中做手脚,把容器和具体类的实现邦定在一起终究会出问题的,所以我把目光放在了const_iterator这个迭代器本身上。
于是,我设计了一个包装类来解决这个问题,基本思想是:包装类实现迭代器的所有concept,并使用迭代器和Functor一起作为参数来构造这个包装类,使得operator *和operator ->的重载中可以使用Functor来临时修改容器中读出来的数据。
完整的代码直接给出来好了,这是一个最简单但可用的类:
程序代码
template <typename ContainerType, typename Functor>
class const_iterator_wrapper
{
typedef const_iterator_wrapper MyType;
typedef typename ContainerType::const_iterator IteratorType;
typedef typename ContainerType::value_type ValueType;
ValueType value_;
IteratorType it_;
Functor func_;
public:
const_iterator_wrapper(const IteratorType & it, const Functor & func = Functor())
: it_(it)
, func_(func)
, value_()
{
}
const ValueType & operator * ()
{
value_ = *it_;
func_(value_);
return value_;
}
const ValueType * operator -> ()
{
value_ = *it_;
func_(value_);
return &value_;