Правильная перегрузка stringbuf для замены cout в mex-файле MATLAB - PullRequest
8 голосов
/ 28 октября 2008

MathWorks в настоящее время не позволяет использовать cout из mex-файла, когда рабочий стол MATLAB открыт, потому что они перенаправили стандартный вывод. Их текущий обходной путь предоставляет функцию 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());    

Ответы [ 4 ]

9 голосов
/ 28 октября 2008

Вы действительно не хотите перегружать std::stringbuf, вы хотите перегрузить std::streambuf или std::basic_streambuf (если вы хотите поддерживать несколько типов символов), также вам необходимо переопределить метод переполнения.

Но я также думаю, что вам нужно переосмыслить решение вашей проблемы.

cout - это просто ostream, поэтому, если все классы / функции принимают ostream, вы можете передать все, что захотите. например cout, ofstream и т. Д.

Если это слишком сложно, я бы создал свою собственную версию 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 голосов
/ 30 октября 2008

Шейн, большое спасибо за вашу помощь. Вот моя последняя рабочая реализация.

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); 
1 голос
/ 22 декабря 2016

Я немного изменил окончательную реализацию 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";

... и не беспокойся о том, чтобы что-то забыть.

0 голосов
/ 28 октября 2008

cout - поток вывода конкретного символа. Если вы хотите cout для записи в файл, используйте fstream, особенно ofstream. У них тот же интерфейс, который обеспечивает cout. Кроме того, если вы хотите получить их буфер (с помощью rdbuf), вы можете.

...