Search code examples
c++matlabcoutmexstringbuffer

Correctly over-loading a stringbuf to replace cout in a MATLAB mex file


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());    

Solution

  • 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.