如何更改分隔符的位置?

时间:2011-09-08 09:06:32

标签: c++ iterator

这个例子:

#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    int v[] = { 1, 2, 3 };

    std::copy( &v[0], &v[3], std::ostream_iterator< int >( std::cout, "\n " ) );
}

产生下一个输出:

1
 2
 3
 

有没有办法更改示例以使其产生下一个输出?


 1
 2
 3

PS我知道我可以使用for循环,但我对使用算法和迭代器的解决方案感兴趣。

5 个答案:

答案 0 :(得分:3)

如果你想使用C ++ 11,你可以使用lambda。

就像这样:

int v[] = { 1, 2, 3};

std::for_each( &v[0], &v[3], [](int i){ std::cout << " " << i << "\n";} );

答案 1 :(得分:3)

使用std::cout << " "代替std::cout

std::copy(v, v+3, std::ostream_iterator<int>(std::cout << " ", "\n " ) );

此处,表达式std::cout << " "首先计算将单个空间打印到输出的位置,并将评估值std::ostream&传递给std::ostream_iterator

现在输出将正确对齐:

 1
 2
 3

工作代码:http://www.ideone.com/kSdpk

顺便说一下,不要写&v[3]。这会调用Undefined bevahior。写v+3

答案 2 :(得分:3)

使用std::ostream_iterator无法执行此操作。 (恕我直言,应该 是的,但它不存在。)如果你不介意写一个额外的小 功能或类, 您可以使用std::transform,例如:

struct FormatString
{
    std::string operator()( std::string const& original ) const
    {
        return ' ' + original + '\n';
    }
};

//  ...
std::transform(
    v.begin(), v.end(),
    std::ostream_iterator<std::string>( std::cout ), 
    FormatString() );

如果你有C ++ 11,你可以使用lambda作为FormatString

我发现这种情况的需要经常发生,我写了一篇 PatsubstTransformer - 基本上是一个功能对象 实现GNU make的$(patsubst...)函数。所以我愿意 必须写:

std::transform(
    v.begin(), v.end(),
    std::ostream_iterator<std::string>( std::cout ),
    PatsubstTransformer( "%", " %\n" ) );

我发现我经常使用它。 (我还发现更多使用std::transform 适合于std::copy,因为我输出的是a 转化。)

答案 3 :(得分:2)

std::copy之前输出一个空格。

答案 4 :(得分:2)

不,不是真的。 ostream_iterator不可配置。

所以你必须使用其他答案中的前置空间“变通方法”,并手动砍掉最后一行。


BTW It's been noted严格来说,&v[3]由于子表达式v[3]中的隐式解除引用而调用未定义的行为。首选&v[0]+3(或只是v+3) - “拥有”一个指向一个数组末尾的指针是可以的,只要它没有被解除引用。


您可以制作自己的ostream_iterator来执行此操作,如以下示例所示。

是的,它很冗长;但是,您也可以根据自己不断变化的需求进行更改:

#include <iostream>
#include <iterator>
#include <algorithm>

template <class T, class charT = char, class traits = std::char_traits<charT> >
struct ostream_iterator_x
  : std::iterator<std::output_iterator_tag, void, void, void, void> {

    typedef charT char_type;
    typedef traits traits_type;
    typedef std::basic_ostream<charT,traits> ostream_type;

    ostream_iterator_x(ostream_type& s, const charT* pre = 0, const charT* post = 0)
       :    s(s)
       ,  pre(pre)
       , post(post) {};

    ostream_iterator_x(const ostream_iterator_x& x)
       :    s(x.s)
       ,  pre(x.pre)
       , post(x.post) {};

    ~ostream_iterator_x() {}

    ostream_iterator_x& operator=(const T& value) {
       if (pre  != 0) s << pre;
       s << value;
       if (post != 0) s << post;

       return *this;
    }

    ostream_iterator_x& operator*()     { return *this; }
    ostream_iterator_x& operator++()    { return *this; }
    ostream_iterator_x& operator++(int) { return *this; }

  private:
    ostream_type& s;
    const charT* pre;
    const charT* post;
};

int main()
{
    int v[] = { 1, 2, 3 };
    std::copy(v, v+3, ostream_iterator_x<int>(std::cout, " ", "\n"));
}

// Output:
//  1
//  2
//  3

(我使用[n3290: 24.6/2]来确定此工作所需的成员和基本规范,并且符合标准。)

Live demo.