如何更改分隔符的位置?

发布于 2024-12-03 07:22:06 字数 426 浏览 1 评论 0原文

此示例:

#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 循环,但我对使用算法和迭代器的解决方案感兴趣。

This example :

#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 " ) );
}

produces next output :

1
 2
 3
 

Is there a way to change the example to make it produce next output?


 1
 2
 3

PS I know I could use the for loop, but I am interested in a solution that uses algorithms and iterators.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

漫雪独思 2024-12-10 07:22:06

使用 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,则可以对 FormatString 使用 lambda。

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

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

我发现我经常使用这个。 (我还发现使用 std::transform 更多
std::copy 合适,因为我输出的是
转变。)

There is no way to do this with std::ostream_iterator. (IMHO, there should
be, but it's not there.) If you don't mind writing an extra small
function or class,
you can use std::transform, e.g.:

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() );

If you have C++11, you can use a lambda for the FormatString.

I find the need for this occurs often enough that I've written a
PatsubstTransformer—a functional object which basically
implements the $(patsubst...) function of GNU make. So I would just
have to write:

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

I find I use this a lot. (I also find using std::transform more
appropriate than std::copy, since what I'm outputting is a
transformation.)

凡尘雨 2024-12-10 07:22:06

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

例如这样:

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

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

If you want to use C++11 you can use a lambda.

e.g like this:

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

std::for_each( &v[0], &v[3], [](int i){ std::cout << " " << i << "\n";} );
假扮的天使 2024-12-10 07:22:06

使用 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]。这会调用未定义行为。写入v+3

Use std::cout << " ", instead of std::cout as:

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

Here the expression std::cout << " " first evaluates which prints a single space to the output, and the evaluated value which is std::ostream& gets passed to std::ostream_iterator

Now the output will be aligned correctly:

 1
 2
 3

Working code : http://www.ideone.com/kSdpk

By the way, don't write &v[3]. That invokes Undefined bevahior. Write v+3.

愁以何悠 2024-12-10 07:22:06

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

Output a single space before the std::copy.

不如归去 2024-12-10 07:22:06

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

因此,您必须使用其他答案中找到的前置空格“解决方法”,并手动截断最后一行。


顺便说一句 已经注意到,严格来说,&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] 来确定此功能所需的成员和基本规范并符合标准。)

现场演示。

No, not really. ostream_iterator isn't configurable like that.

So you'll have to use the pre-space "workaround" as found in other answers, and manually chop off that final line.


BTW It's been noted that &v[3], strictly speaking, invokes undefined behaviour due to the implicit dereference in the sub-expression v[3]. Prefer &v[0]+3 (or just v+3) — "having" a pointer to one-past-the-end of an array is okay, as long as it's not dereferenced.


You could make your own kind of ostream_iterator that does this, as the following example demonstrates.

Yes, it's verbose; however, you can also change it around however you like to suit your changing needs:

#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

(I used [n3290: 24.6/2] to determine the members and base-specification required for this to work and to be standard-compliant.)

Live demo.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文