我以前曾在Stack Overflow上发布过这篇文章,并且正在考虑提交它以促进更广泛的发行,但我认为最好先把它放在这里进行同行评审,看看是否可以首先进行明显的改进。
// infix_iterator.h
//
#if !defined(INFIX_ITERATOR_H_)
#define INFIX_ITERATOR_H_
#include <ostream>
#include <iterator>
template <class T,
class charT=char,
class traits=std::char_traits<charT> >
class infix_ostream_iterator :
public std::iterator<std::output_iterator_tag,void,void,void,void>
{
std::basic_ostream<charT,traits> *os;
charT const* delimiter;
bool first_elem;
public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_ostream<charT,traits> ostream_type;
infix_ostream_iterator(ostream_type& s)
: os(&s),delimiter(0), first_elem(true)
{}
infix_ostream_iterator(ostream_type& s, charT const *d)
: os(&s),delimiter(d), first_elem(true)
{}
infix_ostream_iterator<T,charT,traits>& operator=(T const &item)
{
// Here's the only real change from ostream_iterator:
// We don't print the delimiter the first time. After that,
// each invocation prints the delimiter *before* the item, not
// after. As a result, we only get delimiters *between* items,
// not after every one.
if (!first_elem && delimiter != 0)
*os << delimiter;
*os << item;
first_elem = false;
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator*() {
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator++() {
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator++(int) {
return *this;
}
};
#endif 这在很大程度上是std::ostream_iterator的替代,唯一的区别是(至少在正常使用中)它只在项之间打印分隔符,而不是在每个项之后。使用它的代码如下所示:
#include "infix_iterator.h"
std::vector<int> numbers = {1, 2, 3, 4};
std::copy(begin(numbers), end(numbers),
infix_ostream_iterator<int>(std::cout, ", "));这样做的动机很简单--在std::ostream_iterator中,您的列表会像1, 2, 3, 4,一样显示出来,但是在infix_iterator中,它会以1, 2, 3, 4的形式出现。
顺便提一句,虽然我在这个演示代码中使用了一些C++11特性,但我认为迭代器本身对C++03应该没问题--不过如果有人发现没有C++11支持的编译器有什么问题,我也想听听。
编辑:如果有人关心,这是包含来自@Konrad和@Loki的输入的新版本。多亏了你们俩。
// infix_iterator.h
#if !defined(INFIX_ITERATOR_H_)
#define INFIX_ITERATOR_H_
#include <ostream>
#include <iterator>
#include <string>
template <class T, class charT=char, class traits=std::char_traits<charT> >
class infix_ostream_iterator :
public std::iterator<std::output_iterator_tag, void, void, void, void>
{
std::basic_ostream<charT,traits> *os;
std::basic_string<charT> delimiter;
std::basic_string<charT> real_delim;
public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_ostream<charT, traits> ostream_type;
infix_ostream_iterator(ostream_type &s)
: os(&s)
{}
infix_ostream_iterator(ostream_type &s, charT const *d)
: os(&s),
real_delim(d)
{}
infix_ostream_iterator<T, charT, traits> &operator=(T const &item)
{
*os << delimiter << item;
delimiter = real_delim;
return *this;
}
infix_ostream_iterator<T, charT, traits> &operator*() {
return *this;
}
infix_ostream_iterator<T, charT, traits> &operator++() {
return *this;
}
infix_ostream_iterator<T, charT, traits> &operator++(int) {
return *this;
}
};
#endif 发布于 2012-06-29 23:41:36
没什么大不了的(只是一些个人意见):
infix_ostream_iterator(ostream_type& s)
: os(&s),delimiter(0), first_elem(true)
{} // ^^^ No Space ^^^Trailing space// Here we have & on the left
infix_ostream_iterator<T,charT,traits>& operator=(T const &item)
// Here we have it on the right
infix_ostream_iterator<T,charT,traits> &operator*() {delimter我在写这个=> delimiter时经常出错。
就像我喜欢每行一条语句一样,我更喜欢初始化程序列表中每行初始化一个变量(更容易阅读)。
infix_ostream_iterator(ostream_type& s, charT const *d)
: os(&s)
, delimiter(d)
, first_elem(true)
{}中删除if
这可能对性能没有什么影响,但我会删除if,因此代码如下所示:
*os << delimter << item;
delimter = actualDelimter;
return *this;在构造时,actualDelimter指向用户提供的字符串(或空字符串),delimter设置为指向空字符串。
发布于 2012-06-29 12:07:53
我在代码中唯一能批评的是,infix操作符和指针/引用声明之间的空格位置不一致。
class charT=char,
public std::iterator<std::output_iterator_tag,void,void,void,void>…等等,缺了空间。
: os(&s),delimiter(0), first_elem(true)…等,空间的使用不一致。
infix_ostream_iterator<T,charT,traits>& operator=(T const &item)
infix_ostream_iterator<T,charT,traits> &operator*() {…等等,&的位置不一致。
我还将统一使用函数定义之间的空行,并删除template <…>块和类头之间以及类定义末尾的空行。
吹毛求疵,当然,但这是唯一的批评。
发布于 2012-07-21 18:23:03
我还声明第一个构造函数为显式构造函数:
explicit infix_ostream_iterator(ostream_type &s)
: os(&s)
{}虽然我可以想象这种迭代器的使用是相当有限的,但是这样您就可以确保不会发生不必要的类型转换。
https://codereview.stackexchange.com/questions/13176
复制相似问题