C++ &引用;结束();反向插入器的迭代器?

C++ &引用;结束();反向插入器的迭代器?,c++,stl,iterator,C++,Stl,Iterator,对于迭代器,例如从std::back\u inserter()返回的迭代器,有什么可以用作“结束”迭代器吗 起初这似乎有点荒谬,但我有一个API: template<typename InputIterator, typename OutputIterator> void foo( InputIterator input_begin, InputIterator input_end, OutputIterator output_begin, Outpu

对于迭代器,例如从
std::back\u inserter()
返回的迭代器,有什么可以用作“结束”迭代器吗

起初这似乎有点荒谬,但我有一个API:

template<typename InputIterator, typename OutputIterator>
void foo(
    InputIterator input_begin,
    InputIterator input_end,
    OutputIterator output_begin,
    OutputIterator output_end
);
模板
福娃(
输入计数器输入\u开始,
输入计数器输入端,
输出计数器输出\u开始,
输出计数器输出端
);
foo
对输入序列执行一些操作,生成输出序列。(谁的长度已知于
foo
,但可能等于或不等于输入序列的长度。)

例如,
output\u end
参数的取值是一个奇怪的部分:
std::copy
不会这样做,并且假设您不会将其传递为垃圾
foo
这样做是为了提供范围检查:如果传递的范围太小,它会以防御编程的名义抛出异常。(而不是潜在地覆盖内存中的随机位。)

现在,假设我想传递
foo
一个反向插入器,特别是来自
std::vector
的反向插入器,它在内存约束之外没有限制。我仍然需要一个“end”迭代器——在本例中,它是一个永远不会比较相等的迭代器。(或者,如果我有一个
std::vector
,但长度有限制,也许有时它会比较相等?)


我该怎么做呢?我确实有能力更改
foo
的API-最好不要检查范围,而是提供另一种方法来获得所需的输出范围?(这对于原始数组来说是必需的,但对于向量中的反向插入器来说不是必需的。)这看起来不太健壮,但我正在努力使“健壮”(如上)工作。

如果
foo
正在检查
距离(输出开始,输出结束)
足够大以包含结果,您可以使用什么作为“结束”迭代器?一个
back\u插入器
在末尾添加元素;根据定义,
back\u inserter
添加元素的位置与序列末尾之间的
距离为
0

在我看来,带有std::copy的
foo
签名
foo(InIt,InIt,OutIt)
是您最好的选择。对于大多数算法来说,您只想在性能调试中在调试生成中进行这种范围检查,而一个像样的标准库实现(如VisualC++标准库)已经在调试构建中提供了大量的范围检查。
或者,您可以创建一个
back\u inserting\u foo(InIt,InIt,Container)
,尽管为此创建一个特例会有点不寻常,并且会给函数用户带来更大的负担,让他们知道不同类型的迭代器需要使用哪个重载。

您可以避免更改
foo()
的API,在运行过程中执行安全检查,检查当前输出!=在写出每个元素之前(见下文),输出结束,而不是在开始时用
距离()检查一次

这样做需要编写您自己的“迭代器适配器”,以提供一个“增强的”输出迭代器,该迭代器可以测试它是否在其有效范围的末尾。然后,您将正确地将模板类型名从“代码> ExtPutter程序> /CODE >改为 SuffuutPutter(<代码>)——尽管这只是文档,因为它是不能在C++中执行的。我们区分“有界”迭代器对和“无界”迭代器对:对于后者,没有两个迭代器会比较相等,事实上,第二个迭代器除了它的类型之外,永远不需要任何其他迭代器

/* Metafunction for determining whether the range has a fixed endpoint.
 * Assume all iterators are bounded except for OutputIterators. */
template <typename Tag>
struct helper {
    static bool value = true;
};

template <>
struct helper<output_iterator_tag> {
    static bool value = false;
};

template <typename It>
struct is_bounded {
    static bool value = helper<typename iterator_traits<It>::iterator_category>::value;
};

/* Wraps an output iterator. */
template<typename It, bool BOUNDED = is_bounded<It>::value>
class safe_output_iterator {
    typedef typename iterator_traits<It>::value_type value_type;

public:
    explicit safe_output_iterator(It iter, size_t limit = 0) : iter_(iter), limit_(limit) {}

    safe_output_iterator& operator++() {  /* Preinc */
        ++iter_;
        return *this;
    }

    safe_output_iterator operator++(int) {  /* Postinc */
        safe_output_iterator temp(*this);
        ++iter_;
        return temp;
    }

    /* Trick: Deferencing returns the same object, so that operator=() works */
    safe_output_iterator& operator*() {
        return *this;
    }

    /* Will be called despite "dereferencing" this iterator object */
    safe_output_iterator& operator=() {
        /* Insert check for limit == 0 here if you want */
        --limit_;
        return *_iter;
    }

    /* Addition to the OutputIterator concept. */
    bool operator==(safe_output_iterator const& x) {
        return BOUNDED && limit_ == x.limit_;
    }

    bool operator!=(safe_output_iterator const& x) {
        return !(*this == x);
    }

private:
    It iter_;
    size_t limit_;
};

/* Helper function templates to avoid typing out long typenames */

/* Handle iterators */
template <typename It>
safe_output_iterator<It> soi_begin(It it, size_t limit = 0) {
    return safe_output_iterator<It>(it, limit);
}

template <typename It>
safe_output_iterator<It> soi_end(It it, size_t limit = 0) {
    return safe_output_iterator<It>(it, limit);
}

/* Handle STL containers like vector and list */
template <typename C>
safe_output_iterator<It> soi_begin_cont(C cont) {
    return safe_output_iterator<typename C::iterator>(cont.begin(), cont.size());
}

template <typename C>
safe_output_iterator<It> soi_end_cont(C cont) {
    /* Actually the iterator supplied (here cont.end()) is unimportant... */
    return safe_output_iterator<typename C::iterator>(cont.end());
}
/*用于确定范围是否具有固定端点的元函数。
*假设除输出迭代器外,所有迭代器都是有界的*/
模板
结构辅助程序{
静态布尔值=真;
};
模板
结构辅助程序{
静态布尔值=假;
};
模板
结构是有界的{
静态bool value=helper::value;
};
/*包装输出迭代器*/
模板
类安全\u输出\u迭代器{
typedef typename迭代器_traits::value_type value_type;
公众:
显式安全输出迭代器(It-iter,size-t-limit=0):iter(iter),limit(limit){
安全输出迭代器和运算符++(){/*Preinc*/
++国际热核实验堆;
归还*这个;
}
安全输出迭代器运算符++(int){/*Postinc*/
安全输出迭代器温度(*this);
++国际热核实验堆;
返回温度;
}
/*诀窍:延迟返回相同的对象,因此运算符=()可以工作*/
安全输出迭代器和运算符*(){
归还*这个;
}
/*将被调用,尽管“取消引用”了此迭代器对象*/
安全输出迭代器和运算符=(){
/*如果需要,请在此处插入limit==0的检查*/
--限制!;
返回*\u iter;
}
/*对输出计数器概念的补充*/
布尔运算符==(安全输出迭代器常量&x){
返回有界&&limit \==x.limit \;
}
布尔运算符!=(安全输出迭代器常量&x){
返回!(*this==x);
}
私人:
It iter!;
尺寸限制;
};
/*帮助器函数模板,以避免键入长的类型名*/
/*句柄迭代器*/
模板
安全输出迭代器soi\U begin(It,大小限制=0){
返回安全输出迭代器(it,limit);
}
模板
安全输出迭代器soi\U end(It,大小限制=0){
返回安全输出迭代器(it,limit);
}
/*处理向量和列表等STL容器*/
模板
安全输出迭代器soi开始控制(C控制){
返回安全输出迭代器(cont.begin(),cont.size());
}
模板
安全输出迭代器soi结束控制(C控制){
/*实际上,提供的迭代器(此处cont.end())并不重要*/
返回安全输出迭代器(cont.end());
}
您现在可以编写如下代码:

vector<int> u(10, 42), v(ENOUGH_SPACE), w, x(ENOUGH_SPACE);

// Explicit iterator pair; bounded
foo(u.begin(), u.end(), soi_begin(v.begin(), ENOUGH_SPACE), soi_end(v));

// Explicit iterator pair; unbounded (2nd iterator ignored, but we need the type)
foo(u.begin(), u.end(), soi_begin(w.back_inserter()), soi_end(w.back_inserter()));

// Use whole container
foo(u.begin(), u.end(), soi_begin_cont(x), soi_end_cont(x));
向量u(10,42),v(足够的空间),w,x(足够的空间)
template <typename InIt1, InIt2, OutIt1, OutIt2>
void foo(InIt1 in_begin, InIt2 in_end, OutIt1 out_begin, OutIt2 out_end) { }
class back_inserter_end 
    : std::iterator<std::output_iterator_tag, void>
{ };

bool operator==(back_inserter_end, back_inserter_end) { return true;  }
bool operator!=(back_inserter_end, back_inserter_end) { return false; }

template <typename Container>
bool operator==(const back_insert_iterator<Container>&, back_inserter_end) { 
     return false; 
}

template <typename Container>
bool operator==(back_inserter_end, const back_insert_iterator<Container>&) { 
    return false; 
}

template <typename Container>
bool operator!=(const back_insert_iterator<Container>&, back_inserter_end) { 
    return true; 
}

template <typename Container>
bool operator!=(back_inserter_end, const back_insert_iterator<Container>&) { 
    return true; 
}
foo(it, it, std::back_inserter(v), back_inserter_end());