How are iomanip functions Implemented?
Asked Answered
R

1

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:

Rivers answered 30/3, 2015 at 3:4 Comment(5)
They're actually using helper functions/classes and specialized operator<<() / operator>>() overloads for these.Landmass
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.Boettcher
@Boettcher What is this xalloc madness of which you speak? I read cplusplus.com's description of the xalloc but that really didn't clarify anything for me.Rivers
@JonathanMee, I've never used it. Just a way of storing arbitrary information in the stream AFAIK. The pword page has an example, as does cppreference.Boettcher
@Boettcher 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.Rivers
F
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

Flogging answered 30/3, 2015 at 3:24 Comment(3)
"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.Landmass
@πάνταῥεῖ I meant manipulators that take parameters. In that case, you'd need to overload std::ostream& std::ostream::operator<<( std::ostream& (*fp)(std::ostream&, param1, param2... )), which is not allowed.Flogging
@RemyLebeau I think it can, at least I believe it is not against the standard. Here is something I stumbled upon: https://mcmap.net/q/1316278/-definition-of-friend-inside-classFlogging

© 2022 - 2024 — McMap. All rights reserved.