问题
MathWorks currently doesn't allow you to use cout
from a mex file when the MATLAB desktop is open because they have redirected stdout. Their current workaround is providing a function, mexPrintf, that they request you use instead. After googling around a bit, I think that it's possible to extend the std::stringbuf
class to do what I need. Here's what I have so far. Is this robust enough, or are there other methods I need to overload or a better way to do this? (Looking for portability in a general UNIX environment and the ability to use std::cout
as normal if this code is not linked against a mex executable)
class mstream : public stringbuf {
public:
virtual streamsize xsputn(const char *s, std::streamsize n)
{
mexPrintf("*s",s,n);
return basic_streambuf<char, std::char_traits<char>>::xsputn(s,n);
}
};
mstream mout;
outbuf = cout.rdbuf(mout.rdbuf());
回答1:
You don't really want to overload std::stringbuf
, you want to overload std::streambuf
or std::basic_streambuf
(if you want to support multiple character types), also you need to override the overflow method as well.
But I also think you need to rethink your solution to your problem.
cout
is just an ostream
, so if all classes / functions takes an ostream
then you can pass in anything you like. e.g. cout
, ofstream
, etc
If that's too hard then I would create my own version of cout
, maybe called mycout
that can be defined at either compiler time or runtime time (depending on what you want to do).
A simple solution may be:
#include <streambuf>
#include <ostream>
class mystream : public std::streambuf
{
public:
mystream() {}
protected:
virtual int_type overflow(int_type c)
{
if(c != EOF)
{
char z = c;
mexPrintf("%c",c);
return EOF;
}
return c;
}
virtual std::streamsize xsputn(const char* s, std::streamsize num)
{
mexPrintf("*s",s,n);
return num;
}
};
class myostream : public std::ostream
{
protected:
mystream buf;
public:
myostream() : std::ostream(&buf) {}
};
myostream mycout;
And the cout version could just be:
typedef std::cout mycout;
A runtime version is a bit more work but easily doable.
回答2:
Shane, thanks very much for your help. Here's my final working implementation.
class mstream : public std::streambuf {
public:
protected:
virtual std::streamsize xsputn(const char *s, std::streamsize n);
virtual int overflow(int c = EOF);
};
...
std::streamsize
mstream::xsputn(const char *s, std::streamsize n)
{
mexPrintf("%.*s",n,s);
return n;
}
int
mstream::overflow(int c)
{
if (c != EOF) {
mexPrintf("%.1s",&c);
}
return 1;
}
...
// Replace the std stream with the 'matlab' stream
// Put this in the beginning of the mex function
mstream mout;
std::streambuf *outbuf = std::cout.rdbuf(&mout);
...
// Restore the std stream buffer
std::cout.rdbuf(outbuf);
回答3:
I have changed the OP's final implementation a little bit, adding a constructor and destructor. Creating an object of this class automatically replaces the stream buffer in std::cout
, and when the object goes out of scope, the original stream buffer is restored. RAII!
class mxstreambuf : public std::streambuf {
public:
mxstreambuf() {
stdoutbuf = std::cout.rdbuf( this );
}
~mxstreambuf() {
std::cout.rdbuf( stdoutbuf );
}
protected:
virtual std::streamsize xsputn( const char* s, std::streamsize n ) override {
mexPrintf( "%.*s", n, s );
return n;
}
virtual int overflow( int c = EOF ) override {
if( c != EOF ) {
mexPrintf( "%.1s", & c );
}
return 1;
}
private:
std::streambuf *stdoutbuf;
};
To use the stream buffer in a MEX-file, simply:
mxstreambuf mout;
std::cout << "Hello World!\n";
... and don't worry about forgetting anything.
回答4:
cout
is a particular character output stream. If you want a cout
that writes to a file, use an fstream, particularly an ofstream. They have the same interface that cout
provides. Additionally, if you want to grab their buffer (with rdbuf
) you can.
来源:https://stackoverflow.com/questions/243696/correctly-over-loading-a-stringbuf-to-replace-cout-in-a-matlab-mex-file