Правильная перегрузка stringbuf для замены cout в mex-файле MATLAB.
-
04-07-2019 - |
Вопрос
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());
Решение
Вы действительно не хотите перегружать 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;
Версия во время выполнения немного сложнее, но легко выполнима.
Другие советы
Шейн, большое спасибо за твою помощь.Вот моя последняя рабочая реализация.
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);
Я немного изменил окончательную реализацию 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";
... и не беспокойся о том, чтобы что-то забыть.
cout
- это поток вывода конкретного символа. Если вам нужен cout
, который пишет в файл, используйте < code> fstream , в частности ofstream
. Они имеют тот же интерфейс, что и cout
. Кроме того, если вы хотите получить их буфер (с помощью rdbuf
), вы можете.