C++ - Send data in one ostream to another ostream

荒凉一梦 提交于 2020-12-12 03:39:49

问题


I don't understand what this ostream function declaration means:

ostream& operator<< (ostream& (*pf)(ostream&));

(specifically, the (*pf)(ostream&) part). I want to do something like:

void print(ostream& os){
    cout << os;
}

but I get the error:

 Invalid operands to binary expression ('ostream' . . . and 'ostream')

回答1:


I don't understand what this ostream function declaration means:

ostream& operator<< (ostream& (*pf)(ostream&));

Have you seen functions like std::endl, std::flush, std::hex, std::dec, std::setw...? They can all be "sent" to a stream using "<<", then they get called with the stream as a function argument and do their magic on the stream. They actually match the ostream& (*pf)(ostream&) argument above, and that operator's the one that lets them be used. If we look at the Visual C++ implementation...

 _Myt& operator<<(_Myt& (__cdecl *_Pfn)(_Myt&))
 {
      return ((*_Pfn)(*this));
 }

...you can see if just calls the function, passing the stream it's used on as an argument. The functions are expected to return a reference to the same stream argument, so that further << operations may be chained, or the stream may be implicitly converted to bool as a test of stream state.

See http://en.cppreference.com/w/cpp/io/manip for more information about io manipulators.

You wanted help with:

void print(ostream& os){
    cout << os;
}

The issue here is that you're sending the ostream argument to another stream - cout - and it doesn't know what you want it to do with it.

To send the current content of os to cout, try:

void print(ostream& os){
    cout << os.rdbuf();
}

Or if you want to print some actual data to the stream represented by the argument:

void print(ostream& os){
    os << "show this!\n";
}

print(std::cout);   // to write "show this!\n" to `std::cout`
print(std::cerr);   // to write "show this!\n" to `std::cerr`



回答2:


What the declaration means.

The formal argument …

ostream& (*pf)(ostream&)

declares an argument named pf which is a pointer, to which you can apply an argument parenthesis with an ostream& argument, which constitutes a call that returns an ostream& as its result.

It can be simplified to just …

ostream& pf(ostream&)

where you can more easily see that it's a function.

The drawback is that this form is seldom used, so not everybody is aware that it decays to the first form (much the same as e.g. int x[43] as a formal argument type is effectively the same as just int x[] because both these forms decay to just int* x in the function type, so that in the function body you can even increment that x).


What it’s used for.

A function of the above form is usually an output stream manipulator. That means, you can pass it to the << output operator. What happens then is just that << calls that function, with the stream as argument, as specified by C++11 §27.7.3.6.3/1 and 2:

basic_ostream<charT,traits>& operator<< (basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&))

  1. Effects: None. Does not behave as a formatted output function (as described in 27.7.3.6.1).

  2. Returns: pf(*this).

There is also an overload of << that takes a similar function, but with std::basic_ios& argument and result, and one that takes a function with std::ios_base argument and result.

Class std::ios_base is the base of the iostreams class hierarchy and the standard manipulators defined at that level are …:

  • Format flag manipulators:
    boolalpha, noboolalpha, showbase, noshowbase, showpoint, noshowpoint, showpos, noshowpos, skipws, noskipws, uppercase, nouppercase, unitbut and nounitbuf.

  • Adjustment field manipulators:
    internal, left and right.

  • Numeral system base manipulators:
    dec, hex and oct.

  • Floating point number presentation manipulators:
    fixed, scientific, hexfloat and defaultfloat.

Manipulators that take user arguments don’t follow this form and those that the standard provides are in a separate header called <iomanip>.

Example: a user-defined manipulator.

Code:

#include <iostream>
#include <string>
// With Visual C++, if necessary define __func__ as __FUNCTION__.
using namespace std;

class Logger
{
private:
    string  funcname_;
    static int call_level;

    auto
    static indent( ostream& stream )
        -> ostream&
    { return (stream << string( 4*call_level, ' ' )); }

public:
    Logger( string const& funcname )
        : funcname_( funcname )
    {
        clog << indent << "-> " << funcname_ << endl;
        ++call_level;
    }

    ~Logger()
    {
        --call_level;
        clog << indent << "<- " << funcname_ << endl;
    }
};

int Logger::call_level = 0;

#define WITH_LOGGING Logger logging( __func__ )

void c() { WITH_LOGGING; }
void b() { WITH_LOGGING; c(); }
void a() { WITH_LOGGING; b(); }

auto main() -> int { a(); }

Output, which shows the calls and returns, nicely indented:

-> a
    -> b
        -> c
        <- c
    <- b
<- a



回答3:


The parameter portion of the declaration:

ostream& operator<< (ostream& (*pf)(ostream&));

is a function pointer syntax.

The expression:

ostream& (*pf)(ostream&)

Declares a pointer to a function, pf, that takes an ostream& parameter and returns a reference to an ostream.

If I declare a function:

ostream& my_function(ostream& output);

Then I can pass a pointer to the function as the parameter:

operator<< (my_function);

Read up on function pointer syntax. Search the web and stackoverflow.



来源:https://stackoverflow.com/questions/20850065/c-send-data-in-one-ostream-to-another-ostream

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!