Как записать «n» копии символа в ostream, как в python

В python следующая инструкция: print 'a'*5 выведет aaaaa. Как написать что-то подобное на C++ в сочетании с std::ostreams, чтобы избежать конструкции for?


person Mihai Bişog    schedule 10.07.2012    source источник
comment
Я просто хочу отметить рэп, который я получил, пытаясь ввести что-то вроде "abc"_s * 3 или std::string ("abc") * 3 для обозначения "abcabcabc" на этот вопрос.   -  person chris    schedule 11.07.2012
comment
@chris: это отчасти потому, что люди не понимают, что перегрузка operator*(string, size_t) для string точно так же плоха (или хороша), как и перегрузка operator+(string, string). Не лучше и не хуже — смысл умножения на натуральное число как многократного сложения — фундаментальная математика, нет оправдания непониманию одного, а не другого. Вероятно, это также отчасти потому, что ваш вопрос жалуется на стандарт и предлагает изменить его (ни одно из них не по теме), в дополнение к вопросу о мотивации :-p   -  person Steve Jessop    schedule 11.07.2012


Ответы (5)


Очевидным способом будет fill_n:

std::fill_n(std::ostream_iterator<char>(std::cout), 5, 'a');

Другой возможностью было бы просто построить строку:

std::cout << std::string(5, 'a');
person Jerry Coffin    schedule 10.07.2012
comment
Есть ли конкретная причина, по которой вы не используете ostreambuf_iterator? - person Columbo; 24.05.2015
comment
@Columbo: Нет, за исключением того, что на самом деле не хочет объяснять разницу между ostream_iterator и ostreambuf_iterator кому-то из Python, которого (в конце концов), вероятно, не волнует разница (хотя, конечно, если бы кто-нибудь спросил, Я бы, вероятно, отослал их к ответу Xeo. - person Jerry Coffin; 24.05.2015
comment
Возможно, удивительно, но первый приводит к значительно более эффективному объектному коду как в GCC, так и в Clang. Они не только могут развернуть операцию std:fill_n для потока, но, что более важно, позволяют избежать динамического выделения памяти, необходимого для построения (а затем уничтожения) строки. (Почему они не могут исключить динамическое выделение памяти для постоянной строки времени компиляции... Я уверен, что есть веская причина...) - person Cody Gray; 03.10.2020
comment
@CodyGray: если вы видите динамическое выделение для строки длиной 5 (постоянная времени компиляции или что-то другое), вы должны получить лучшую реализацию. Оптимизация коротких строк хорошо известна уже несколько десятилетий. По общему признанию, gcc потребовалось долго времени, чтобы добавить его, но даже он делает это в течение достаточно долгого времени. - person Jerry Coffin; 04.10.2020

Используйте какой-нибудь хитрый способ: os << setw(n) << setfill(c) << ""; Где n - количество символов c для записи

person PiotrNycz    schedule 10.07.2012
comment
Сложно и проблематично, поскольку символ заполнения не сбрасывается автоматически, когда вы закончите. - person Jerry Coffin; 11.07.2012
comment
@Джерри, это правда. Но это не серьезная проблема, так как setfill(' ') после работы здесь. Кстати, решение с fill_n может быть нарушено os << setw(5) << left << fill_n(...) - созданием a aaaa: D... - person PiotrNycz; 11.07.2012

В C++20 для этого можно использовать std::format. :

std::cout << std::format("{:a<5}", "");

Вывод:

aaaaa

А пока вы можете использовать библиотеку {fmt}, на которой основан std::format. {fmt} также предоставляет функцию print, которая делает это еще проще и эффективнее (godbolt):

fmt::print("{:a<5}", "");

Отказ от ответственности: я автор {fmt} и C++20 std::format.

person vitaut    schedule 16.12.2020

Вы можете сделать что-то подобное, перегрузив оператор * для std::string. Вот небольшой пример

#include<iostream>
#include<string>
std::string operator*(const std::string &c,int n)
{
    std::string str;
    for(int i=0;i<n;i++)
    str+=c;
    return str;
}
int main()
{
    std::string str= "foo";
    std::cout<< str*5 <<"\n";
}
person nims    schedule 10.07.2012

Стандарт не предусматривает какого-либо элегантного способа. Но одна из возможностей (моя любимая) — использовать такой прокси-объект

class repeat_char
{
public:
    repeat_char(char c, size_t count) : c(c), count(count) {}
    friend std::ostream & operator<<(std::ostream & os, repeat_char repeat)
    {
        while (repeat.count-- > 0)
            os << repeat.c;
        return os;
    }
private:
    char c;
    size_t count;
};

а затем использовать его таким образом

std::cout << repeat_char(' ', 5);
person Youda008    schedule 19.06.2021