Search code examples
c++printfprecisioncoutiomanip

Stream Precision Modifier for strings


Lets say I have string foo("lorem ipsum"). Now i want to print a maximum number of characters from foo, let's say x which is guaranteed to be smaller than foo.size().

This is very continent in printf:

printf("%.*s", x, foo.data());

But the only way I can find to do this in a stream is to construct a temporary string:

cout << string(foo, x);

Is there a manipulator that will let me set the precision for streams, or is constructing a temporary string all that's available to me?


Solution

  • There is no "stream manipulator" to cut off strings after a specified width.

    What you're looking for is basically string_view(1), that is some light weight substring wrapper which is ostream-able.

    The following line would print the first x characters of foo without copying it to a temporary string, as long as the guarantee you mention (x >= foo.size()) holds:

    cout << string_view(foo.data(), x);
    

    In case the guarantee doesn't hold anymore, use setw to fill the field with whitespaces when the string is shorter, in order to print a fixed field length of x characters. The string_view constructor needs a properly bound-limited length since it doesn't know the size of the "real" std::string object, thus we use min to limit x to the length of the string:

    cout << setw(x) << string_view(foo.data(), min(x, foo.size()));
    

    If you don't want to or can't use string_view, you can write your own light weight wrapper just for the purpose of printing a substring with ostream.

    class substr {
         const std::string & s;
         std::size_t len;
    
         friend std::ostream& operator<<(std::ostream& os, const substr &ss) {
             std::copy(ss.s.begin(), ss.s.begin() + std::min(ss.len, ss.s.size()),
                       std::ostream_iterator<char>(os));
             return os;
         }
    public:
         substr(const std::string & s, std::size_t len) : s(s), len(len) {}
    };
    

    The usage is then:

    cout << substr(foo, x);
    

    Live Example


    (1) This class is currently experimental and not yet in the standard. As far as I know, it probably will be in C++17 and is available as std::experimental::string_view in <experimental/string_view> since g++ 4.9 when using -std=c++1y or 17.