Wie überprüfe ich, ob C ++ 11 unterstützt wird?

104

Gibt es eine Möglichkeit, beim Kompilieren festzustellen, ob der Compiler bestimmte Funktionen von C ++ 11 unterstützt? Zum Beispiel so etwas:

#ifndef VARIADIC_TEMPLATES_SUPPORTED

#error "Your compiler doesn't support variadic templates.  :("

#else

template <typename... DatatypeList>
class Tuple
{
    // ...
}

#endif
Maxpm
quelle
2
Sie könnten einen Header namens "assert_variadic_template_support.hpp" haben, den Sie einschließen und in dem Sie so etwas tun können template <typename... Test> struct compiler_must_support_variadic_templates;. Ein Syntaxfehler würde das Problem schnell aufdecken. (
Nebenbei bemerkt
Der "richtige" Weg, um dieses Problem zu lösen, ist ein Konfigurationstest.
Joseph Garvin

Antworten:

125

Es gibt eine Konstante mit dem Namen , __cplusplusdass C ++ Compiler auf die Version des C eingestellt sollte ++ Standard unterstützt diese sehen

#if __cplusplus <= 199711L
  #error This library needs at least a C++11 compliant compiler
#endif

Es ist in Visual Studio 2010 SP1 auf 199711L eingestellt, aber ich weiß nicht, ob Anbieter so mutig sein werden, es bereits zu erhöhen, wenn sie nur (teilweise) Unterstützung auf Compilerebene im Vergleich zu einer Standard-C ++ - Bibliothek mit allen C ++ 11-Änderungen haben .

Daher bleiben die in einer anderen Antwort erwähnten Boost-Definitionen der einzig vernünftige Weg, um herauszufinden, ob beispielsweise C ++ 11-Threads und andere spezifische Teile des Standards unterstützt werden.

Cygon
quelle
37
C ++ 11 setzt den Wert von __cplusplusauf 201103L. Dies bestätigt die vollständige Übereinstimmung mit dem Standard von 2011; Es sagt nichts über teilweise Konformität oder Compiler-Erweiterungen aus. Wenn eingestellt __cplusplusist 201103L, passt sich der Compiler entweder vollständig an oder er belügt Sie. Wenn dies nicht der Fall ist, können Sie nicht wirklich sagen, welche Funktionen unterstützt werden.
Keith Thompson
1
g ++ 4.7.x (und vermutlich neuer) legt dies fest, wenn die -std=c++11Option angegeben wird (möglicherweise auch mit -std=gnu++11). Sie tun dies, obwohl sie noch nicht vollständig sind (4.8 bringt uns viel näher). Hinweis - Es gibt eine Lücke zwischen dem, was der Compiler unterstützt, und dem, was in der Standardbibliothek verfügbar ist. Sowohl 4.7.x als auch 4.8.x fehlen derzeit die Regex-Unterstützung - aber das ist eine Bibliothek, keine Compiler-Funktion.
Nathan Ernst
1
Ich frage mich, warum dies nicht die akzeptierte Antwort ist. Sie können diesen Vorschlag auch verwenden , um Ihre Antwort weiter zu verbessern. Er ist sehr gut.
Iharob Al Asimi
1
@KeithThompson Für mich beide Code :: Blocks und Visual Studio den Wert des __cpluspluszu 199711Lfür C ++ 11
Donald Duck
3
@ DonaldDuck: Genau genommen, nein, das tun sie nicht. Ein Compiler, der __cplusplusauf gesetzt 199711List , ist kein konformer C ++ 11-Compiler. Sie haben wahrscheinlich Optionen, damit sie sich richtig verhalten.
Keith Thompson
39

Wie im C ++ 11- Standard (§iso.16.8) angegeben:

Der Name __cplusplus wird beim Kompilieren einer C ++ - Übersetzungseinheit auf den Wert 201103L definiert .

Mit dem Wert dieses Makros können Sie überprüfen, ob der Compiler C ++ 11-kompatibel ist.

Wenn Sie nach einer Standardmethode suchen, um zu überprüfen, ob der Compiler eine beliebige Teilmenge der C ++ 11-Funktionen unterstützt, gibt es meines Erachtens keine standardmäßige, portable Methode. Sie können die Dokumentation des Compilers oder die Header-Dateien der Standardbibliothek überprüfen, um weitere Informationen zu erhalten.

Paolo M.
quelle
2
Beispielsweise wird static_assert in VS2010 und in allen c ++ 11-Copilern unterstützt. Wenn Sie also nach einem Wert von __cplusplus suchen, der größer oder gleich dem in VS2010 festgelegten Wert ist (dh> = 199711L), kann dies in Ordnung sein.
Paolo M
33

Ich weiß, dass dies eine sehr alte Frage ist, aber diese Frage wird oft gesehen und die Antworten sind etwas veraltet.

Neuere Compiler mit dem C ++ 14-Standard bieten eine Standardmethode zum Überprüfen von Funktionen, einschließlich C ++ 11-Funktionen. Eine umfassende Seite finden Sie unter https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations

Zusammenfassend ist für jede Funktion ein Standardmakro definiert, mit dem Sie überprüfen können #ifdef. Um beispielsweise nach benutzerdefinierten Literalen zu suchen, können Sie verwenden

#ifdef __cpp_user_defined_literals
Jarryd
quelle
1
Das wusste ich nicht. Ich denke, dass diese einfache Funktion zu spät kommt, aber dennoch sehr nützlich sein kann, insbesondere das __has_include()Makro.
Prapin
22

Zur Überprüfung der Unterstützung C ++ 14 und andere. Testen auf GCC 5.2.1.

#include <iostream>

int main(){
        #if __cplusplus==201402L
        std::cout << "C++14" << std::endl;
        #elif __cplusplus==201103L
        std::cout << "C++11" << std::endl;
        #else
        std::cout << "C++" << std::endl;
        #endif

        return 0;
}
kurono267
quelle
17

Sie können dies verwenden:

#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
    cout << "C++11 is supported";
#else
    cout << "C++11 is not supported";
#endif

Für C ++ 11 setzen die meisten Compiler außer Visual Studio das __cplusplusMakro auf 201103L, aber jede Version von Visual Studio legt es auf 199711Lden Wert fest, der für andere Compiler vor C ++ 11 verwendet wurde. Dieser Code vergleicht das _cplusplusMakro mit 201103Lallen Compilern außer Visual Studio. Wenn der Compiler Visual Studio ist, wird überprüft, ob die Version von Visual Studio später als 2015 ist, der ersten Version von Visual Studio, die C ++ 11 vollständig unterstützt (für Visual Studio 2015 hat das _MSC_VERMakro den Wert 1900, siehe diese Antwort ).

Donald Duck
quelle
1
Diese Antwort ist falsch. Bei g++ -std=c++98GCC 4.8 wird falsch gedruckt C++11 is supported.
Punkte
1
@pts Sorry, nur ein Tippfehler. Es sollte jetzt behoben sein.
Donald Duck
7

Wenn Sie Boost.Config nicht verwenden möchten und nach Compilern testen müssen, die C ++ 11 unterstützen, reicht es aus, den Wert der Konstante zu überprüfen __cplusplus. Ein Compiler unterstützt jedoch möglicherweise die meisten gängigen Funktionen des C ++ 11-Standards, unterstützt jedoch nicht die gesamten Spezifikationen. Wenn Sie die Unterstützung für bestimmte Visual Studio-Compiler aktivieren möchten, die noch nicht 100% den C ++ 11-Spezifikationen entsprechen, verwenden Sie das folgende Codefragment, mit dem Sie in Visual Studio 2013 kompilieren können:

#if defined(_MSC_VER)
#   if _MSC_VER < 1800 
#       error This project needs atleast Visual Studio 2013
#   endif
#elif __cplusplus <= 199711L
#   error This project can only be compiled with a compiler that supports C++11
#endif

Eine vollständige Liste der Versionen des Compilers für Visual Studio finden Sie unter So erkennen Sie, ob ich Code mit Visual Studio 2008 kompiliere

Vamshi Krishna
quelle
6

In der traditionellen Linux / Unix-Welt wird Autoconf traditionell verwendet, um das Vorhandensein von Bibliotheken und Compilerfunktionen sowie Fehler zu testen, die in eine config.h eingefügt werden, die Sie bei Bedarf in Ihren Dateien verwenden.

diverscuba23
quelle
2
Ja, Autoconf kann zum Testen von Funktionen verwendet werden, aber Sie müssen dafür sorgen, dass das entsprechende Makro für Fehler oder Erfolge generiert wird, das dann mit dem obigen Code getestet werden kann. Diese Antwort allein fügt also keine Informationen hinzu.
Martin York
3
@LokiAstari: So funktioniert Autoconf nicht. Autoconf bietet Makros, mit denen Sie Ihr Konfigurationsskript eine Testquelldatei kompilieren lassen und die #define basierend auf dem Erfolg der Kompilierung auf 0 oder 1 setzen können. Die Antwort von diverscuba23 liefert Informationen, indem darauf hingewiesen wird, dass das OP nach einer suboptimalen Lösung für das eigentliche Problem greift.
Joseph Garvin
1

Wenn Sie nach einer Verfügbarkeit der C ++ 11-Bibliothek suchen (keine Sprachfunktion), z. B. nach dem <array>Header, können Sie dies tun #if __has_include(<array>).

Manchmal überprüft #if __cplusplus >= 201103Lwürden Sie sagen , dass Sie C ++ verwenden , 11 aber auch andere Einstellungen wie die Standardbibliothek Version Einstellung in Xcode kann immer noch nicht die neuen Bibliotheken zur Verfügung haben ( die meisten von ihnen in verschiedenen Namen verfügbar sind , dh <tr1/array>)

Yairchu
quelle