在MATLAB mex文件中正确地重载stringbuf以替换cout

8
MathWorks目前不允许您在MATLAB桌面打开时从mex文件使用cout,因为他们已经重定向了stdout。他们提供了一个函数mexPrintf作为解决方法。经过一番搜索,我认为可以扩展std::stringbuf类来实现我需要的功能。以下是我目前的进展。这个代码足够健壮吗?还是需要重载其他方法或更好的方法来实现?(希望在通用UNIX环境中具有可移植性,并且如果此代码未与mex可执行文件链接,则能够像正常情况下一样使用std::cout
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());    
4个回答

9
您不需要重载std::stringbuf,而是需要重载std::streambufstd::basic_streambuf(如果您想支持多个字符类型),并且还需要覆盖overflow方法。
但我认为您需要重新考虑解决问题的方案。 cout只是一个ostream,因此如果所有的类/函数都接受ostream,那么您可以传入任何您喜欢的东西。例如:coutofstream等。
如果这太难了,那么我会创建自己的版本cout,可能称为mycout,可以在编译时或运行时定义(取决于您想要做什么)。
一个简单的解决方案可能是:
#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;

而 cout 版本只需要:

typedef std::cout mycout;

一个运行时版本需要更多的工作,但很容易实现。

9

Shane,非常感谢您的帮助。这是我最终的工作实现。

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

恢复std流缓冲区被证明非常重要。如果不这样做,我的mex函数似乎会出现某种内存问题,并在重新编译时导致matlab崩溃。 - Alec Jacobson

2

我稍微修改了OP的最终实现,添加了构造函数和析构函数。创建这个类的对象会自动替换std::cout中的流缓冲区,当对象超出作用域时,原始流缓冲区会被恢复。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;
};

要在MEX文件中使用流缓冲区,只需:

mxstreambuf mout;
std::cout << "Hello World!\n";

不用担心漏掉任何事情。

关于it技术的部分内容需要您提供具体的翻译文本。

0

cout 是一个特定的字符输出流。如果你想要一个写入文件的 cout,可以使用 fstream,特别是 ofstream。它们提供了与 cout 相同的接口。此外,如果你想要获取它们的缓冲区(使用 rdbuf),也可以这样做。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接