Эффективным способом применения ограничена строкой оператор форматирования для использования с <<?

#c #string-formatting #iostream

#c #форматирование строки #iostream

Вопрос:

Я ищу что-то, где:

 string pearString ("pear");
string bananaString ("banana");

cout << ???? 5 ??? pearString ??????? << "[end]" << endl;
cout << ???? 5 ??? bananaString ??????? << "[end]" << endl;
  

Будет (для некоторой последовательности символов кода ???) вывод:

 pear[end]
banan[end]
  

Но я бы хотел, чтобы это работало без необходимости выполнять операцию подстроки, которая копировала бы строку. Если я чего-то не упустил, для этого нет спецификатора форматирования. (Спецификатор setw заполняет более короткие строки, но позволяет переполнять более длинные.)

«Хитрой» вещью, о которой я подумал, было бы создать облегченный класс-оболочку с собственным оператором вывода потока. Для этого потребуется (неконстантная) ссылка на строку и ограничение в ее конструкции. Затем оператор вывода проверит длину, выполнит стандартный вывод, если он меньше или равен пределу. Если бы оно было больше, оно бы временно вставило нулевой символ в позицию длины, достаточную для выполнения вывода … а затем вернуло исходный символ обратно.

(ОБНОВЛЕНИЕ: на самом деле эта идея не сработала бы, поскольку << игнорирует встроенные нули.)

В любом случае идея того, как это будет выглядеть, будет:

 cout << strlimiter(5, pearString) << "[end]" << endl;
cout << strlimiter(5, bananaString) << "[end]" << endl;
  

Какие-нибудь более чистые решения, которые работали бы с постоянными строками и не выводили бы данные из-под вас? Что-то, что использует другие перехваты или приемы расширения iostream? Это где-то покрыто библиотекой?


ОБНОВЛЕНИЕ: я упустил из виду write метод iostream вместо << , так что вот несколько примеров кода:

 #include <iostream>
#include <string>
#include <algorithm>
using namespace std;

class strlimiter
{
    friend ostreamamp; operator<< (ostreamamp; os, strlimiter sl);

private:
    const stringamp; data;
    size_t limit;

public:
    strlimiter(const stringamp; data, size_t limit) : data(data), limit(limit) {}
    ~strlimiter() {}
};

ostreamamp; operator<< (ostreamamp; os, strlimiter sl) {
   return os.write(sl.data.c_str(), min(sl.data.length(), sl.limit));
}

int main() {
    string pearString ("pear");
    string bananaString ("banana");

    cout << strlimiter(pearString, 5) << "[end]" << endl;
    cout << strlimiter(bananaString, 5) << "[end]" << endl;

    return 0;
}
  

Еще какие-нибудь хитрости, которые могли бы снизить затраты во время выполнения?

Ответ №1:

Почему бы просто не использовать write функцию-член ostream :

 cout.write(bananaString.c_str(),5);
  

Возможно, удивительно, что вы даже можете поместить это в начало цепочки вставки. Взяв за основу ваш пример, вы можете использовать следующую несколько запутанную цепочку:

 cout.write(bananaString.c_str(),5) << "[end]" << endl;
  

Комментарии:

1. Использование write — это определенно то, о чем я должен был подумать, << по какой-то причине я застрял. Однако метод write игнорирует встроенные нули и фактически помещает указанное вами количество байтов в поток. Таким образом, его нельзя использовать для прямого решения этой проблемы без какой-либо упаковки для проверки длины…

2. @HostileFork: operator<< для std::string также игнорирует встроенные нули. Если вам нужно другое поведение, то лучше всего проверить длину перед раздачей. Я сомневаюсь, что вы можете добиться большей эффективности.

3. Правильно, просто говорю, что я не могу просто использовать вашу вторую строку cout.write(bananaString.c_str(),limit) в общем случае попытки печати до предела…

Ответ №2:

Для вашего класса-оболочки в перегруженном operator<< , вместо использования << в строке, используйте ostream::write функцию.

 the_stream.write(the_string.c_str(), the_size);
  

Комментарии:

1. D’oh. Ага. Спасибо. Добавлен некоторый код, не стесняйтесь добавлять любые другие замечания или идеи по улучшению…