Jak sprawdzić obsługę języka C ++ 11?


104

Czy istnieje sposób na wykrycie w czasie kompilacji, czy kompilator obsługuje niektóre funkcje C ++ 11? Na przykład coś takiego:

#ifndef VARIADIC_TEMPLATES_SUPPORTED

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

#else

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

#endif

2
Możesz mieć nagłówek o nazwie „assert_variadic_template_support.hpp”, który możesz dołączyć, a wewnątrz zrobić coś podobnego template <typename... Test> struct compiler_must_support_variadic_templates;. Błąd składni szybko ujawniłby problem. (Tak na marginesie, właściwy komunikat o błędzie jest znacznie lepszy.)
GManNickG,

„Właściwym” sposobem rozwiązania tego problemu jest test konfiguracji.
Joseph Garvin,

Odpowiedzi:


125

Istnieje stała o nazwie, __cplusplusktórą kompilatory C ++ powinny ustawić na wersję obsługiwanego standardu C ++. Zobacz to

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

Jest ustawiony na 199711L w Visual Studio 2010 SP1, ale nie wiem, czy dostawcy będą tak śmiali, aby go już zwiększyć, jeśli mają tylko (częściowe) wsparcie na poziomie kompilatora w porównaniu ze standardową biblioteką C ++ ze wszystkimi zmianami w C ++ 11 .

Tak więc definicje Boost wspomniane w innej odpowiedzi pozostają jedynym rozsądnym sposobem ustalenia, czy istnieje na przykład wsparcie dla wątków C ++ 11 i innych określonych części standardu.


37
C ++ 11 ustawia wartość __cplusplusto 201103L. To potwierdza pełną zgodność ze standardem 2011; nie mówi o częściowej zgodności ani o rozszerzeniach kompilatora. Jeśli __cplusplusjest ustawiona na 201103L, to albo kompilator w pełni się zgadza, albo cię okłamuje. Jeśli tak nie jest, nie możesz tak naprawdę powiedzieć, które funkcje obsługuje.
Keith Thompson

1
g ++ 4.7.x (i prawdopodobnie nowszy) ustawia to, gdy -std=c++11podano opcję (może również -std=gnu++11). Robią to, mimo że nie są do końca kompletne (4.8 znacznie przybliża nas). Uwaga - istnieje luka między tym, co obsługuje kompilator, a tym, co jest dostępne w bibliotece standardowej. W obu wersjach 4.7.xi 4.8.x brakuje obecnie obsługi wyrażeń regularnych - ale jest to biblioteka, a nie funkcja kompilatora.
Nathan Ernst

1
Zastanawiam się, dlaczego nie jest to akceptowana odpowiedź. Możesz również skorzystać z tej sugestii, aby jeszcze bardziej ulepszyć swoją odpowiedź, jest bardzo dobra.
Iharob Al Asimi

1
@KeithThompson Dla mnie zarówno Code :: Blocks, jak i Visual Studio ustawiły wartość __cplusplusto 199711Ldla języka C ++ 11.
Kaczor Donald

3
@DonaldDuck: Ściśle mówiąc, nie, nie robią. Kompilator, który ustawia się __cplusplusna, 199711Lnie jest zgodnym kompilatorem C ++ 11. Prawdopodobnie mają opcje, aby zachowywać się poprawnie.
Keith Thompson

39

Jak stwierdzono w standardzie C ++ 11 (§iso.16.8):

Nazwa __cplusplus jest definiowana na wartość 201103L podczas kompilowania jednostki tłumaczeniowej C ++.

Dzięki wartości tego makra można sprawdzić, czy kompilator jest zgodny z C ++ 11.

Jeśli szukasz standardowego sposobu sprawdzenia, czy kompilator obsługuje jakikolwiek podzbiór funkcji C ++ 11, myślę, że nie ma standardowego, przenośnego sposobu; możesz sprawdzić dokumentację kompilatorów lub pliki nagłówkowe bibliotek std, aby uzyskać więcej informacji.


2
Na przykład static_assert jest obsługiwany w VS2010 i we wszystkich kopilatorach C ++ 11. Tak więc, jeśli sprawdzisz wartość __cplusplus większą lub równą niż ta ustawiona w VS2010 (tj.> = 199711L), możesz być w porządku.
Paolo M

33

Wiem, że to bardzo stare pytanie, ale często można je spotkać, a odpowiedzi są nieco nieaktualne.

Nowsze kompilatory ze standardem C ++ 14 mają standardowy sposób sprawdzania funkcji, w tym funkcji C ++ 11. Obszerna strona znajduje się pod adresem https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations

Podsumowując, każda funkcja ma zdefiniowane standardowe makro, które można sprawdzić #ifdef. Na przykład, aby sprawdzić literały zdefiniowane przez użytkownika, możesz użyć

#ifdef __cpp_user_defined_literals

1
Nie wiedziałem tego. Myślę, że ta prosta funkcja pojawi się późno, ale nadal może być bardzo przydatna, zwłaszcza __has_include()makro.
prapin

22

Sprawdź obsługę C ++ 14 i innych. Testowanie na 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;
}

17

Możesz użyć tego:

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

W przypadku języka C ++ 11 większość kompilatorów, z wyjątkiem programu Visual Studio, ustawia __cplusplusmakro na 201103L, ale każda wersja programu Visual Studio ustawia go 199711Ljako wartość używaną przez inne kompilatory przed C ++ 11. Ten kod porównuje _cplusplusmakro ze 201103Lwszystkimi kompilatorami z wyjątkiem programu Visual Studio, a jeśli kompilatorem jest program Visual Studio, sprawdza, czy wersja programu Visual Studio jest nowsza niż 2015, pierwsza wersja programu Visual Studio, która w pełni obsługuje C ++ 11 (dla programu Visual Studio 2015, _MSC_VERmakro ma wartość 1900, zobacz odpowiedź ).


1
Ta odpowiedź jest nieprawidłowa. W g++ -std=c++98przypadku GCC 4.8 drukuje nieprawidłowo C++11 is supported.
pkt

1
@pts Przepraszamy, tylko literówka. Należy to teraz naprawić.
Kaczor Donald

7

Jeśli nie chcesz używać Boost.Config i potrzebujesz przetestować kompilatory obsługujące C ++ 11, wystarczy sprawdzić wartość stałej __cplusplus. Jednak kompilator może obsługiwać większość popularnych funkcji standardu C ++ 11, ale nie obsługuje wszystkich specyfikacji. Jeśli chcesz włączyć obsługę określonych kompilatorów programu Visual Studio, które nie są jeszcze w 100% zgodne ze specyfikacjami C ++ 11, użyj następującego fragmentu kodu, który umożliwia kompilację w programie Visual Studio 2013:

#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

Pełną listę wersji kompilatora dla programu Visual Studio podano w artykule Jak wykryć, czy kompiluję kod w programie Visual Studio 2008


6

W tradycyjnym świecie Linuksa / Uniksa autoconf jest tradycyjnie używany do testowania obecności bibliotek i funkcji kompilatora oraz błędów umieszczania ich w pliku config.h, którego używasz w swoich plikach w razie potrzeby.


2
Tak, autoconf może być używany do testowania funkcji, ale musisz sprawić, by wygenerował odpowiednie makro na wypadek awarii lub sukcesów, które można następnie przetestować za pomocą powyższego kodu. Tak więc sama odpowiedź nie dostarcza żadnych informacji.
Martin York,

3
@LokiAstari: Nie tak działa autoconf. Autoconf udostępnia makra, które pozwalają skryptowi konfiguracyjnemu skompilować testowy plik źródłowy i ustawić #define na 0 lub 1 w zależności od powodzenia kompilacji. Odpowiedź diverscuba23 dostarcza informacji, wskazując, że PO dąży do nieoptymalnego rozwiązania rzeczywistego problemu.
Joseph Garvin,


1

Kiedy sprawdzasz dostępność biblioteki C ++ 11 (nie funkcję języka), na przykład <array>nagłówek, możesz #if __has_include(<array>).

Czasami sprawdzenie #if __cplusplus >= 201103Lpowie Ci, że używasz C ++ 11, ale inne ustawienia, takie jak ustawienie standardowej wersji biblioteki w Xcode, mogą nadal nie mieć dostępnych nowych bibliotek (większość z nich jest dostępna pod różnymi nazwami, tj. <tr1/array>)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.