Получить размер элемента в выходном потоке C ++ - PullRequest
3 голосов
/ 25 сентября 2019

Я форматирую вывод журнала.Я хочу, чтобы конечный результат выглядел так:

Foo.................................12.1
Bar....................................4
Foo Bar............................42.01

Общая ширина постоянна, но оба параметра (имя и значение) имеют разные размеры.Есть ли чистый способ получить ширину заданного параметра, однажды включенного в std :: ostream?

#include <iostream>

struct Entry {
    std::string name_;
    double value_;
};

constexpr int line_width = 30;

std::ostream& operator<<(std::ostream& log, const Entry& e)
{
    log << e.name_
        << std::string(line_width - e.name_.size(), '.') \\ should subtract the width of e.value_
        << e.value_;
    return log;
}

int main()
{
    Entry foo    = { "Foo", 12.1 };
    Entry bar    = { "Bar", 4};
    Entry foobar = { "Foo Bar", 42.01};

    std::cout << foo << '\n' << bar << '\n' << foobar << '\n';
}

Код выше не будет работать, потому что я не вычитал ширину значения.Я думал о написании функции, которая будет делать что-то вроде этого:

template <typename T>
int get_width(std::ostream& log, T value)
{
    // 1. use tellp to get initial stream size
    // 2. insert the value in the stream
    // 3. use tellp to get final stream size  
    // 4. remove the value from the stream (is that even possible?)
    // 5. return the size = final - initial 
}

Есть ли чистый способ достичь моей цели?

Ответы [ 2 ]

2 голосов
/ 25 сентября 2019

Как сообщалось, вопрос представляет собой проблему XY, так как вам не нужно знать ширину, чтобы получить желаемый результат.Для этого должно быть достаточно знать общую ширину поля и использовать подходящий символ fill .

Это должно работать для вас:

std::ostream& operator<<(std::ostream& log, const Entry& e)
{
    auto beg = log.tellp();
    log << e.name_;
    auto len = log.tellp() - beg;
    auto oldFill = log.fill();
    auto oldWidth = log.width();
    log.fill('.');
    log.width(line_width - len);
    log << e.value_;
    log.fill(oldFill);
    log.width(oldWidth);
    return log;
}

[Живой пример]

Обратите внимание, что это зависит от того, действительно ли поток способен сообщать действительные значения с помощью tellp().Файловые потокиstd::cout подключен к терминалу нет.

1 голос
/ 25 сентября 2019

Вы можете создать одну строку, содержащую «имя», и одну строку, содержащую «значение».

Тогда легко вычислить общую длину этих двух строк, и из этого вычислить пространство, необходимое междуим.

...