Как реализованы функции iomanip?

Некоторые стандартные функции iomanip принимают параметр.

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

Когда я искал определение функции setw, например, в http://en.cppreference.com, он перечисляет возвращаемый тип как неуказанный, и он также перечисляет только один аргумент, а не принимает параметр stream&. Как это работает?

Примечание для читателя:

На этот вопрос есть отличный ответ, но для человека, который ищет этот вопрос; этот ответ будет полезен только в сочетании со следующими функциями, предоставляемыми ios_base:


person Jonathan Mee    schedule 30.03.2015    source источник
comment
На самом деле они используют вспомогательные функции/классы и специализированные перегрузки operator<<()/operator>>() для них.   -  person πάντα ῥεῖ    schedule 30.03.2015
comment
В отличие от пользовательского параметра форматирования, поток имеет функцию-член width, действующую как метод доступа и модификатор. Насколько я знаю, пользовательские дополнения в значительной степени должны использовать xalloc et. др.   -  person chris    schedule 30.03.2015
comment
@chris Что это за xalloc безумие, о котором ты говоришь? Я прочитал cplusplus.com описание xalloc, но это действительно ничего не прояснило для меня.   -  person Jonathan Mee    schedule 30.03.2015
comment
@JonathanMee, я никогда им не пользовался. Просто способ хранения произвольной информации в потоке AFAIK. На странице pword есть пример, как и на cppreference.   -  person chris    schedule 30.03.2015
comment
@chris Я смог использовать ответ здесь только благодаря вашим комментариям. Так что большое вам спасибо! Я включил их в вопрос, чтобы помочь будущим читателям пройти более легкий путь, чем копаться в комментариях.   -  person Jonathan Mee    schedule 26.11.2018


Ответы (1)


Вот простой пример определяемого пользователем манипулятора, который принимает один параметр, определенный с помощью класса:

#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);
}

Манипуляторы, не принимающие никаких параметров, могут быть просто реализованы как

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

Это связано с тем, что basic_ostream::operator<< имеет перегрузку, которая принимает указатель на функцию std::ostream& (*fp)(std::ostream&) в качестве правой части (например, манипулятор).

PS: Стандартная библиотека C++ Н. Джосуттиса очень подробно описывает, как работают манипуляторы/настраиваемые манипуляторы, см. гл. 15.6.3 Пользовательские манипуляторы

person vsoftco    schedule 30.03.2015
comment
не уверен, что вы можете использовать только функцию Можно. Тогда используется перегрузка оператора для конкретного указателя функции. Это для случаев без параметров. - person πάντα ῥεῖ; 30.03.2015
comment
@πάνταῥεῖ Я имел в виду манипуляторы, которые принимают параметры. В этом случае вам нужно будет перегрузить std::ostream& std::ostream::operator<<( std::ostream& (*fp)(std::ostream&, param1, param2... )), что не разрешено. - person vsoftco; 30.03.2015
comment
@RemyLebeau Я думаю, что может, по крайней мере, я считаю, что это не противоречит стандарту. Вот что я наткнулся: stackoverflow.com/a/12182338/3093378 - person vsoftco; 30.03.2015