2016-08-05 39 views
3

Ich habe eine sehr einfache Protokollierungsklasse geschrieben.Wie vermeide ich # including <sstream> dank einer Template-Funktion?

Die Logging-Klasse verfügt über eine Funktion, die wie folgt aussieht:

template <typename T, typename... Args> 
void log (T && first, Args &&... rest) { 
    log (std::forward <T> (first)); 
    log (std::forward <Args> (rest)...); 
} 

template <typename T> 
void log (T && last) { 
    /* use <sstream>'s std::ostringstream to convert each T to its string 
    representation, then print it via a callback. */ 
} 

Da meine Logging-Klasse ist wahrscheinlich in meinem Programm häufig verwendet werden, ich versuche, die Menge an Code zu reduzieren, die anheften geht zu auf jede Übersetzungseinheit als Ergebnis von #includ -ing meine Logger-Datei.

Ich habe es geschafft, alle #include Aussagen außer <string> aus der Header-Datei und in der Implementierungsdatei zu bewegen, außer die Gesamtheit <sstream> und alle seine Abhängigkeiten, die für die Durchführung dieser Vorlage Memberfunktion erforderlich sind, .

Ich habe explizit instanziiert alle Überladungen, die ich brauche, aber wenn ich hoffe, meine Logger mit String-Literalen zu verwenden, dann denke ich, ich muss explizit eine Vorlage für jede n in const char (&) [n] instanziieren. Oder #include <type_traits> für std::decay. :(

Ist es möglich, zu vermeiden, dass <sstream> in alle TUs zu ziehen, dass mein Logger zu verwenden? Wie?

+1

Haben Sie gedacht, 'std :: to_string()' (C++ 11) zu verwenden? Sehen Sie, ob das hilft, '' zu entfernen. Für die anderen Klassen können Sie die klassenspezifische 'public' Methode' to_string() 'implementieren. – iammilind

+0

Vielleicht könnte [PIMPL idiom] (https://en.wikipedia.org/wiki/Opaque_pointer) relevant sein –

+0

@iammilind Hmm. Ich könnte die Konvertierungen machen, um mich selbst zu zeichnen (mit 'to_string()' und so weiter). Ich brauche _really_ nicht '' um das zu tun. Für alles andere wäre eine "to_string" (nicht?) - Mitgliedsfunktion vollkommen akzeptabel. –

Antwort

1

Eine Möglichkeit, in meinem Projekt, das ich übernehmen müssen, ist std::to_string() von C++ 11 zu verwenden. Diese kann Nutzung von <sstream> vermeiden. Sie können nur <string> Header enthalten sind. Für bestimmte Klassen, können Sie ihre eigenen öffentlichen Methoden to_string() s implementieren.

Aber Android-Version (verwendeten wir bis Mitte 2016) nicht std::to_string() hatte Leider sogar mit C++ 11. In diesem Fall müssen wir uns auf sstream verlassen ncluding <sstream> in der Header-Datei von unten template & Makro Trick (Spielzeug-Code) mit:

// header.h 
template<typename ostringstream, typename T> 
std::string my_to_string (T&& value) 
{ 
    ostringstream oss; 
    oss << value; 
    return oss.str(); 
} 

#define my_to_string(X) my_to_string<std::ostringstream>(X) 

nun in allen Implementierungen müssen Sie <sstream> und verwenden, wie unten setzen,:

// implementation.cpp 
#include<sstream> 
int main() 
{ 
    double d = 1.2345; 
    std::string s = my_to_string(d); 
    std::cout << "converted: " << s << "\n"; 
} 

Demo.

+0

'to_string' ist nur ein Wrapper für' sprintf' (explizit wie vom Standard definiert), Sie können also auch 'sprintf' an dieser Stelle verwenden. –

+0

Mit dieser Lösung muss ich überall "" #include, was den Punkt besiegt, es nicht einfach in die Header-Datei aufzunehmen. Interessanter Trick mit der Template Instanziierung. –

+0

@MaxBozzi, ja das ist richtig.Es gibt etwas, das '' genannt wird, das Ihnen in gewissem Maße hilft, bestimmte 'std ::' vorwärts zu deklarieren. Aber wenn Sie Objekte von '' verwenden wollen, müssen Sie es auf die eine oder andere Art "einschließen". Aber wenn Ihre Implementierung 'to_string()' erlaubt, dann können Sie '' vermeiden. @uhoh, ich wollte es nur mehr C++ behalten, daher 'to_string()'. – iammilind