2008-10-28 20 views
8

MathWorks erlaubt derzeit nicht, cout aus einer mex-Datei zu verwenden, wenn der MATLAB-Desktop geöffnet ist, weil sie stdout umgeleitet haben. Ihre aktuelle Problemumgehung bietet eine Funktion mexPrintf, that they request you use instead. Nachdem ich etwas gegoogelt habe, denke ich, dass es möglich ist, die Klasse std :: stringbuf zu erweitern, um das zu tun, was ich brauche. Hier ist, was ich bisher habe. Ist das robust genug oder gibt es andere Methoden, die ich überlasten muss oder einen besseren Weg, dies zu tun? (Suche nach Portabilität in einer allgemeinen UNIX-Umgebung und die Fähigkeit, std :: cout als normal zu verwenden, wenn dieser Code nicht gegen einen mex ausführbaren verknüpft ist)Korrekten Überladen eines Stringbuf zum Ersetzen von cout in einer MATLAB-Mex-Datei

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

Antwort

9

Sie wollen std :: stringbuf nicht wirklich überladen, wenn Sie std :: streambuf oder std :: basic_streambuf überladen wollen (wenn Sie mehrere Zeichentypen unterstützen wollen), müssen Sie auch die Überlaufmethode als überschreiben Gut.

Aber ich denke auch, dass Sie Ihre Lösung für Ihr Problem überdenken müssen.

cout ist nur ein Ostream, wenn also alle Klassen/Funktionen eine Ostream haben, dann können Sie alles einfügen, was Sie wollen. z.B. cout, ofstream, etc.

Wenn das zu schwer ist, dann würde ich meine eigene Version von cout erstellen, vielleicht mycout genannt, die entweder zur Compilerzeit oder zur Laufzeit definiert werden kann (je nachdem, was Sie tun wollen).

kann eine einfache Lösung sein:

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

Und die cout Version könnte nur sein:

typedef std::cout mycout; 

Eine Runtime-Version ist ein bisschen mehr Arbeit, aber leicht machbar.

0

cout ist ein besonderer Zeichen Ausgabestrom. Wenn Sie eine cout möchten, die in eine Datei schreibt, verwenden Sie eine fstream, insbesondere eine ofstream. Sie haben die gleiche Schnittstelle, die cout bietet. Zusätzlich können Sie, wenn Sie ihren Puffer (mit rdbuf) greifen möchten.

9

Shane, vielen Dank für Ihre Hilfe. Hier ist meine letzte Arbeitsimplementierung.

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

Die Wiederherstellung des Standardstrompuffers erwies sich als sehr wichtig. Ohne dies zu tun, schien meine Mex-Funktion ein gewisses Speicherproblem zu bekommen und stürzte Matlab beim erneuten Kompilieren ab. –

1

ich die endgültige Umsetzung des OP ein wenig geändert haben, eine Zugabe Konstruktor und Destruktor. Das Erstellen eines Objekts dieser Klasse ersetzt automatisch den Stream-Puffer in std::cout, und wenn das Objekt den Gültigkeitsbereich verlässt, wird der ursprüngliche Stream-Puffer wiederhergestellt. 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; 
}; 

Um den Strompuffer in einer MEX-Datei, verwenden Sie einfach:

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

... und keine Sorge über alles zu vergessen.