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

发布于 2024-07-08 16:45:38 字数 694 浏览 17 评论 0原文

MathWorks 目前不允许您在 MATLAB 桌面打开时使用 mex 文件中的 cout,因为它们已重定向 stdout。 他们当前的解决方法是提供一个函数 mexPrintf,他们要求您使用该函数。 经过一番谷歌搜索后,我认为可以扩展 std::stringbuf 类来完成我需要的操作。 这是我到目前为止所拥有的。 这是否足够强大,或者是否有其他我需要重载的方法或更好的方法来做到这一点? (寻求通用 UNIX 环境中的可移植性以及正常使用 std::cout 的能力(如果此代码未链接到 mex 可执行文件)

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

看轻我的陪伴 2024-07-15 16:45:38

您并不是真的想重载 std::stringbuf,而是想重载 std::streambufstd::basic_streambuf (如果您想要支持多种字符类型),还需要重写溢出方法。

但我也认为你需要重新考虑你的问题的解决方案。

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;

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

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.

深海少女心 2024-07-15 16:45:38

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

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

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); 
来日方长 2024-07-15 16:45:38

我稍微改变了OP的最终实现,添加了构造函数和析构函数。 创建此类的对象会自动替换 s​​td::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";

...并且不用担心忘记任何内容。

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.

十年九夏 2024-07-15 16:45:38

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文