Corretamente sobre-carregamento de um stringbuf para substituir cout em um arquivo mex MATLAB
-
04-07-2019 - |
Pergunta
MathWorks atualmente não permite que você use cout
de um arquivo mex quando o desktop MATLAB está aberto, porque eles têm redirecionado stdout. Sua solução atual está fornecendo uma função, mexPrintf, que pedem que você usar em vez . Depois de pesquisar um pouco, eu acho que é possível estender a classe std::stringbuf
para fazer o que eu preciso. Aqui está o que eu tenho até agora. É este o suficiente robusta, ou existem outros métodos que eu preciso sobrecarga ou uma melhor maneira de fazer isso? (Olhando para a portabilidade em um ambiente geral UNIX ea capacidade de utilização std::cout
como normal se este código não está ligada contra um mex executável)
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());
Solução
Você realmente não quer std::stringbuf
sobrecarga, você quer std::streambuf
sobrecarga ou std::basic_streambuf
(se você quiser suportar vários tipos de caracteres), também é preciso substituir o método de estouro bem.
Mas também acho que você precisa repensar a sua solução para o seu problema.
cout
é apenas um ostream
, por isso, se todas as classes / funções leva um ostream
então você pode passar em qualquer coisa que você gosta. por exemplo. cout
, ofstream
, etc
Se isso é muito difícil, então eu iria criar minha própria versão de cout
, talvez chamado mycout
que pode ser definido em qualquer tempo compilador ou tempo de execução (dependendo do que você quer fazer).
Uma solução simples pode ser:
#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;
E a versão cout só poderia ser:
typedef std::cout mycout;
A versão de tempo de execução é um pouco mais de trabalho, mas facilmente factível.
Outras dicas
Shane, muito obrigado por sua ajuda. Aqui está a minha aplicação de trabalho final.
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);
Eu mudei implementação final do OP um pouco, adicionando um construtor e destruidor. Criando um objeto dessa classe substitui automaticamente o buffer de fluxo em std::cout
, e quando o objeto sai do escopo, o buffer de fluxo original é restaurada. 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;
};
Para usar o buffer de fluxo em um MEX-file, simplesmente:
mxstreambuf mout;
std::cout << "Hello World!\n";
... e não se preocupe em esquecer nada.