9

Some of the standard iomanip functions take take a parameter.

I'd like to know how this is accomplished, for instance, can I do something similar with a function? That's really the solution that I needed for this answer, but I couldn't figure out how to do this.

When I looked up the definition for setw function for example in http://en.cppreference.com it lists the return type as "unspecified", and it also only lists one argument, rather than also taking a stream& parameter. How does this work?

Note to the reader:

This question has an excellent answer but to the individual looking up this question; this answer will only be useful in combination with the following functionality provided by ios_base:

vitaut
  • 37,224
  • 19
  • 144
  • 248
Jonathan Mee
  • 35,107
  • 16
  • 95
  • 241
  • 1
    They're actually using helper functions/classes and specialized `operator<>()` overloads for these. – πάντα ῥεῖ Mar 30 '15 at 03:05
  • 1
    Unlike a custom formatting option, the stream has a `width` member function acting as an accessor and mutator. As far as I know, custom additions pretty much have to use `xalloc` et. al. – chris Mar 30 '15 at 03:09
  • @chris What is this `xalloc` madness of which you speak? I read http://www.cplusplus.com's [description of the `xalloc`](http://www.cplusplus.com/reference/ios/ios_base/xalloc/) but that really didn't clarify anything for me. – Jonathan Mee Mar 30 '15 at 03:16
  • 1
    @JonathanMee, I've never used it. Just a way of storing arbitrary information in the stream AFAIK. The [`pword`](http://www.cplusplus.com/reference/ios/ios_base/pword/) page has an example, as does [cppreference](http://en.cppreference.com/w/cpp/io/ios_base/xalloc). – chris Mar 30 '15 at 03:19
  • @chris I was only able to use the answer here thanks to your comments. So thanks you so much! I've incorporated them into the question with the intent of helping future readers along an easier path than digging through the comments. – Jonathan Mee Nov 26 '18 at 19:51

1 Answers1

10

Here is a simple example of a user-defined manipulator that takes one parameter defined using a class:

#include <iostream>

class putX // injects some `X`s into the stream
{
    std::size_t _n;
public:
    explicit putX(std::size_t n): _n(n) {}
    std::size_t getn() const {return _n;}
    friend std::ostream& operator<<(std::ostream& os, const putX& obj)
    {
        std::size_t n = obj.getn();
        for (std::size_t i = 0; i < n; ++i)
            os << 'X';
        return os;
    }
};

int main()
{
    std::cout << putX(10) << " test " << putX(10);
}

Manipulators that take no parameters can simply be implemented as

std::ostream& custom_manip(std::ostream& os) { // do something with os and return os;}

That's because basic_ostream::operator<< has an overload that takes a pointer-to-function std::ostream& (*fp)(std::ostream&) as its right hand side (e.g., a manipulator)

PS: The C++ Standard Library by N. Josuttis describes how manipulators/custom manipulators work in great detail, see Sec. 15.6.3 User-Defined Manipulators

Remy Lebeau
  • 454,445
  • 28
  • 366
  • 620
vsoftco
  • 52,188
  • 7
  • 109
  • 221
  • _"not sure if you can only use a function"_ You can. There's an operator overload for the particular function pointer used then. It's for cases without parameters. – πάντα ῥεῖ Mar 30 '15 at 03:31
  • 1
    @πάνταῥεῖ I meant manipulators that take parameters. In that case, you'd need to overload `std::ostream& std::ostream::operator< – vsoftco Mar 30 '15 at 03:33
  • @RemyLebeau I think it can, at least I believe it is not against the standard. Here is something I stumbled upon: http://stackoverflow.com/a/12182338/3093378 – vsoftco Mar 30 '15 at 04:14