C++03 / C++11: Einige Fragen beim Schreiben einer Library
-
Hallo Community,
ich programmiere gerade eine Library, und da sie nun so gut wie fertiggestellt ist und ich sie in zwei Versionen veröffentlichen wollte (einmal 03 Standard; einmal 11er Standard), habe ich noch ein paar Fragen bezüglich den Unterschieden zwischen C++03 und C++11. Eines muss jedoch berücksichtigt werden: Auch wenn man einige meiner Probleme mit anderen diversen Libraries (z.B. boost) lösen könnte, verzichte ich darauf, weil ich ganz einfach nicht will, dass meine Library von anderen Libraries abhängig ist. Schließlich bekommt das schlussendlich der Anwender der Library zu spüren, wenn er die benötigten Libraries noch nicht auf seinem PC installiert hat. Ich leg mal los:
Sollte ich ein einziges Projekt der Library haben, wobei ich mit dem
__cplusplus-Makro arbeite, und so zwischen 03 und 11er Standard unterscheide (Vorteil: der Benutzer brauch sich nicht zu scheren, ob sein Compiler nach dem 03- oder 11er-Standard kompiliert; Nachteil: Unleserlich), oder sollte ich doch lieber zwei Projekte erstellen, einmal im 03-Standard und einmal im 11er (Vorteil: Leserlich; Nachteil: Der Benutzer muss die richtige Version auswählen)?std::function<>, das ist doch erst seit C++11 dabei, nicht? Wenn ja, dann wäre die beste Lösung wohl eine eigene Klasse dafür zu bauen, right?std::mutexist erst seit C++11 dabei, aber ich brauch für die 03-Version einen plattformunabhängigen Weg um einige Stellen meiner Library thread-sicher zu machen. Irgendwelche Vorschläge?Variadic Templates braucht meine Library auch. Was die C++03-Version betrifft: Soll ich da einfach einen Haufen Default-Parameter benutzen? Wenn ja, wie viele?
Vermutlich werden im Laufe der Zeit noch einige Fragen auftauchen. Wenns so weit ist und ich selbst die Lösung dafür nicht finde oder ich mir ganz einfach unsicker bin, werde ich diese hier noch hinzufügen.
Liebe Grüße,
I. AM. CUDDLY.
-
ichBinKnuddelig schrieb:
std::mutexist erst seit C++11 dabei, aber ich brauch für die 03-Version einen plattformunabhängigen Weg um einige Stellen meiner Library thread-sicher zu machen. Irgendwelche Vorschläge?Das wird nur mit einer Library oder ähnlichem einigermaßen platformunabhängig funktionieren. Man könnte auch POSIX Threads nehmen. Aber dann nimmt man besser gleich Boost, für die 03er Version, da dies dann zumindest sehr ähnlich wie die C++11 Lösung ist.
Oder wäre OpenMP eine Lösung? Ist von Ansatz allerdings sehr verschieden.
-
ichBinKnuddelig schrieb:
Hallo Community,
Sollte ich ein einziges Projekt der Library haben, wobei ich mit dem__cplusplus-Makro arbeite, und so zwischen 03 und 11er Standard unterscheide (Vorteil: der Benutzer brauch sich nicht zu scheren, ob sein Compiler nach dem 03- oder 11er-Standard kompiliert; Nachteil: Unleserlich), oder sollte ich doch lieber zwei Projekte erstellen, einmal im 03-Standard und einmal im 11er (Vorteil: Leserlich; Nachteil: Der Benutzer muss die richtige Version auswählen)?Ich würde versuchen, die Unterschiede so weit wie möglich wegzuabstrahieren und die unterschiedlichen Implementierungen in Module auszulagern, die du dann einfach je nach System austauschen kannst.
-
ichBinKnuddelig schrieb:
oder sollte ich doch lieber zwei Projekte erstellen, einmal im 03-Standard und einmal im 11er (Vorteil: Leserlich; Nachteil: Der Benutzer muss die richtige Version auswählen)?
Wesentlich wichtigerer Nachteil: Du musst ständig beide Versionen synchron halten. Auch wenn sich nur kleine Dinge unterscheiden, bist du ständig am Code kopieren, musst Bugfixes zwei Mal anwenden, etc. Die Duplikation ist unnötig aufwändig und fehleranfällig.
ichBinKnuddelig schrieb:
Eines muss jedoch berücksichtigt werden: Auch wenn man einige meiner Probleme mit anderen diversen Libraries (z.B. boost) lösen könnte, verzichte ich darauf, weil ich ganz einfach nicht will, dass meine Library von anderen Libraries abhängig ist.
Ohne Bibliotheken und mit C++98 musst du auch bereit sein, auf Features (wie Multithreading) zu verzichten.
ichBinKnuddelig schrieb:
Variadic Templates braucht meine Library auch. Was die C++03-Version betrifft: Soll ich da einfach einen Haufen Default-Parameter benutzen? Wenn ja, wie viele?
Nein, du benutzt einfach keine Variadic Templates und suchst dir andere Lösungen. Hat schliesslich jahrzehntelang auch funktioniert. Natürlich kannst du dir Workarounds schreiben, aber wenn du dich schon bei bedingter Kompilierung um die Übersichtlichkeit des Codes sorgst, solltest du die Emulation von Variadic Templates schnell wieder vergessen

Wenn man bereit ist, syntaktische Kompromisse einzugehen, kann man auch mit C++98 nahezu das Gleiche erreichen (mittels Operatoren).
Was für eine Zielgruppe hast du denn, dass du C++98 unbedingt unterstützen willst? Mit Boost wäre es ja noch erträglich, da du sehr viele Bibliotheks- und teilweise sogar Sprachmittel trotzdem zur Verfügung hast, aber komplett ohne Bibliotheken bist du eben recht stark eingeschränkt.
-
TNA schrieb:
Ich würde versuchen, die Unterschiede so weit wie möglich wegzuabstrahieren und die unterschiedlichen Implementierungen in Module auszulagern, die du dann einfach je nach System austauschen kannst.
Falscher Ansatz.
Das führt dazu, dass sich Leute eigene String-Klassen und sonstige Container (vorzugsweise verlinkte Listen) schreiben.Besser ist ein Header <compat/thread>, der aus einem include <boost/thread.hpp> mit using boost::thread; besteht und analog für C++11.
-
Das Problem ist auch, dass C++11 das Schreiben von Interfaces verändert.
Move-Semantik ist so ein Beispiel. In gewissen Fällen kannst du sie lediglich als optionale Optimierung anbieten, aber bei nichtkopierbaren Klassen verändert sich dadurch die Semantik des Codes.
-
Nexus schrieb:
Das Problem ist auch, dass C++11 das Schreiben von Interfaces verändert.
Move-Semantik ist so ein Beispiel. In gewissen Fällen kannst du sie lediglich als optionale Optimierung anbieten, aber bei nichtkopierbaren Klassen verändert sich dadurch die Semantik des Codes.
Da macht mans einfach wie die Standardlibrary:
Man hat eine C++03-Bibliothek als Basis.Falls C++11 definiert ist (wird glaub irgendwo in __cplusplus verschlüsselt) dann gibts ein paar Zusatz-Features. Das ist bedingte Kompilierung, aber nur in eine Richtung.
Das mit Threads ist bei genauerer Überlegung etwas anders. Vielleicht will ein Librarybenutzer C++11 mit boost::thread verwenden. Wäre es eine Option, eine Thread-Policy zu verwenden?
-
Vergiss C++03 einfach.
-
cooky451 schrieb:
Vergiss C++03 einfach.
YMMD

Variadic Templates braucht meine Library auch. Was die C++03-Version betrifft: Soll ich da einfach einen Haufen Default-Parameter benutzen? Wenn ja, wie viele?
Was brauchst du denn genau an variadic templates? Bestimmt nichts was wirklich nur variadic templates können. Erklär mal anhand eines Beispiels.
-
Sone schrieb:
Was brauchst du denn genau an variadic templates? Bestimmt nichts was wirklich nur variadic templates können. Erklär mal anhand eines Beispiels.
Größtenteils für das Event-System.
Beispiel:template<typename Type, typename = typename std::enable_if<std::is_function<Type>::value>::type> class Event{ ... template<typename... Arguments, typename ResultType = result_type, typename = typename std::enable_if<std::is_same<void, ResultType>::value == true>::type> result_type process(Arguments&&... arguments) const{ for(const auto& function : functions_vector_) function(std::forward<Arguments>(arguments)...); } template<typename... Arguments, typename ResultType = result_type, typename = typename std::enable_if<std::is_same<void, ResultType>::value == false>::type> std::vector<result_type> process(Arguments&&... arguments) const{ std::vector<result_type> results; for(const auto& function : functions_vector_) results.push_back(function(std::forward<Arguments>(arguments)...)); return results; } ... };
-
Also Funktions-Argumente forwarden.
Naja. Gabs schon in Loki (Alexandrescu - Modern C++ Design), halt für Funktionen mit bis zu AFAIK 15 Parametern. Und ohne perfect forwarding natürlich, aber das gibt es in C++03 eben sowieso nicht.
-
void invoke(std::function<void(int)> const& f) { f(4); } ... // Bitte nicht auf is_function<Type>::value testen, ich will das auch mit std::funciton verwenden können!!!111 template<typename Type> class Event{ template <typename Invoker> result_type process(Invoker i) { foreach (f : funcs) i(f); } }@Sone: Seit wann ist Loki ein Massstab?
-
cooky451 schrieb:
Vergiss C++03 einfach.
Thats a good point.
Ich weiß ja nichtmal ob überhaupt jemand irgendwann mal meine Library benutzen möchte. Ich belasse es dann vorerst mal bei C++11 und wenn dann irgendwann mal Bedarf auf C++03 entsteht, kann ich den Kram ja umschreiben.
Haltet ihr das für eine gute Idee?
-
ichBinKnuddelig schrieb:
Haltet ihr das für eine gute Idee?
Ja. Wir haben 2013, so langsam sind C++11-Compiler auch auf trägeren Systemen angekommen*. Die verbliebenen Systeme sind die, die niemals upgraden werden und noch immer mit VS6, GCC3 oder gar mit einer DOS-Version von Turbo-C++ (von anno 1985) arbeiten, weil irgendein Entscheider gegen einen Wechsel ist (oder es ihm einfach egal ist). Die unterstützen dann in der Regel nicht einmal C++98 richtig. Wenn du (mit C++11) maximal portabel bleiben möchtest, dann lass erst einmal Features aus, die nicht in allen großen Compilern (Microsoft, GCC, Clang, eventuell noch Intel und IBM) imlementiert sind.
http://wiki.apache.org/stdcxx/C%2B%2B0xCompilerSupport*: Man denke daran, dass C++11 wesentlich älter ist als 2011 und viele Features davon schon lange vorher verbreitet waren. Bloß eben noch nicht offiziell.
-
@SeppJ
Wir haben ne riesen Code-Base die wir erst vor ein paar Jahren mühsam auf VS 2005 upgegraded haben.
Ein Upgrade auf VS 2012 ist im nächsten Jahr unwahrscheinlich.
Trotzdem würde ich nicht sagen dass unser Code "niemals upgegraded" wird.Auf C++ 03 Systeme Rücksicht nehmen finde ich also nicht ganz verkehrt.
Wobei ich es auch niemandem übel nehme wenn er seine Open-Source (oder auch Closed-Source) C++ Library so programmiert dass z.B. VS 2012 vorausgesetzt wird. Muss jeder für sich entscheiden.
Ich würde aber eben jmd. der gerne Rücksicht nehmen will nicht sagen "vergiss C++ 03", weil das danach klingt als ob es keinen mehr interessieren würde. Was definitiv nicht so ist.
-
Aber prinzipiell hättet ihr einen C++11-Compiler auf dem System (oder könntet einen holen), der hinreichend kompatibel ist, um am Ende alles zusammen zu linken.
Das Interface der Bibliothek darf man natürlich gerne kompatibel zu C++03 halten, aber bei den Interna würde ich keine Rücksicht mehr nehmen.
-
SeppJ schrieb:
Aber prinzipiell hättet ihr einen C++11-Compiler auf dem System (oder könntet einen holen), der hinreichend kompatibel ist, um am Ende alles zusammen zu linken.
Ja.
Nur was nutzt uns das? Man kann nicht einfach VS 2005 und VS 2012 Code zusammenknoten, wenn das Interface C++ ist.
Mit nem C-DLL Interface geht es natürlich, aber es geht hier ja um C++ Libs.Das Interface der Bibliothek darf man natürlich gerne kompatibel zu C++03 halten, aber bei den Interna würde ich keine Rücksicht mehr nehmen.
Siehe oben, ich wüsste nicht was uns das bringen sollte.
-
[quote="SeppJ"]
ichBinKnuddelig schrieb:
Die verbliebenen Systeme sind die, die niemals upgraden werden und noch immer mit VS6, GCC3 oder gar mit einer DOS-Version von Turbo-C++ (von anno 1985) arbeiten, weil irgendein Entscheider gegen einen Wechsel ist (oder es ihm einfach egal ist). Die unterstützen dann in der Regel nicht einmal C++98 richtig.
Ganz so schwarzweiß ist das nicht. Bei uns ist z.B. mit GCC 3.7 erst mal Ende der Fahnenstange, weil die neueren eine älter ABI für ARM nicht mehr unterstützen, die wir benötigen. Damit werden wir manches von C++11 nie nutzen können. Auch gestaltet sich die Anbindung der Standardbibliothek sehr schwierig und kommt erst langsam Schritt für schritt. "Thread" wird es wohl spät bis nie geben, da das mit unserem Jobmanagement konzeptionell nicht zusammenpasst.
-
ichBinKnuddelig schrieb:
std::function<>, das ist doch erst seit C++11 dabei, nicht? Wenn ja, dann wäre die beste Lösung wohl eine eigene Klasse dafür zu bauen, right?boost::functionichBinKnuddelig schrieb:
std::mutexist erst seit C++11 dabei, aber ich brauch für die 03-Version einen plattformunabhängigen Weg um einige Stellen meiner Library thread-sicher zu machen. Irgendwelche Vorschläge?boost::mutexichBinKnuddelig schrieb:
Variadic Templates braucht meine Library auch. Was die C++03-Version betrifft: Soll ich da einfach einen Haufen Default-Parameter benutzen? Wenn ja, wie viele?
Boost.Preprocessor oder Boost.MPL
ichBinKnuddelig schrieb:
Größtenteils für das Event-System.
Beispiel:template<typename Type, typename = typename std::enable_if<std::is_function<Type>::value>::type> class Event{ [...] };Sieht so ähnlich aus wie Boost.Signals2.
Boost hat auch Mittel, um Unterschiede zwischen Implementationen auszugleichen. Da gibt es zum Beispiel
BOOST_CONSTEXPR, einen Ersatz für<cstdint>, Emulation von RValue-Referenzen, Container wievectorund so weiter.Warum nicht einfach Boost nehmen?
-
TyRoXx: Danke für die Vorschläge, aber
ichBinKnuddelig schrieb:
[...] Auch wenn man einige meiner Probleme mit anderen diversen Libraries (z.B. boost) lösen könnte, verzichte ich darauf, weil ich ganz einfach nicht will, dass meine Library von anderen Libraries abhängig ist.[...]

Ich werd erstmal kucken wie sich die Library, die sich an den 11er Standard lehnt in der Öffentlichkeit schlägt, wenn dann wie bereits erwähnt wirklich noch Bedarf an C++03 auftritt geh ich nochmal auf den Thread ein.
Bis dahin nochmals Danke an alle!