Come posso verificare il supporto di C ++ 11?


104

C'è un modo per rilevare in fase di compilazione se il compilatore supporta alcune funzionalità di C ++ 11? Ad esempio, qualcosa del genere:

#ifndef VARIADIC_TEMPLATES_SUPPORTED

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

#else

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

#endif

2
Potresti avere un'intestazione chiamata "assert_variadic_template_support.hpp" che puoi includere e all'interno fare qualcosa di simile template <typename... Test> struct compiler_must_support_variadic_templates;. Un errore di sintassi rivelerebbe rapidamente il problema. (Tanto per
inciso

Il modo "giusto" per risolvere questo problema è un test di configurazione.
Joseph Garvin

Risposte:


125

C'è una costante chiamata __cplusplusche i compilatori C ++ dovrebbero impostare sulla versione dello standard C ++ supportato vedi questo

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

È impostato su 199711L in Visual Studio 2010 SP1, ma non so se i fornitori saranno così audaci da aumentarlo già se hanno solo il supporto (parziale) a livello di compilatore rispetto a una libreria C ++ standard con tutte le modifiche C ++ 11 .

Quindi le definizioni di Boost menzionate in un'altra risposta rimangono l'unico modo sensato per capire se esiste, ad esempio, il supporto per i thread C ++ 11 e altre parti specifiche dello standard.


37
C ++ 11 imposta il valore di __cplusplusa 201103L. Ciò afferma la piena conformità allo standard 2011; non parla di conformità parziale o estensioni del compilatore. Se __cplusplusè impostato su 201103L, allora o il compilatore è completamente conforme o ti sta mentendo. Se non lo è, non puoi davvero dire quali funzionalità supporta.
Keith Thompson

1
g ++ 4.7.x (e presumibilmente più recente) imposta questo quando l' -std=c++11opzione è specificata (può anche con -std=gnu++11). Lo fanno, anche se non sono del tutto completi di funzionalità (4.8 ci avvicina molto). Nota: c'è un divario tra ciò che supporta il compilatore e ciò che è disponibile nella libreria standard. Sia 4.7.x che 4.8.x attualmente mancano del supporto alle espressioni regolari, ma questa è una libreria, non una funzionalità del compilatore.
Nathan Ernst

1
Mi chiedo perché questa non sia la risposta accettata. Inoltre, potresti usare questo suggerimento per migliorare ulteriormente la tua risposta, è molto buono.
Iharob Al Asimi

1
@KeithThompson Per me, entrambi Code :: Blocks e Visual Studio impostare il valore di __cplusplusa 199711Lper C ++ 11.
Paperino

3
@DonaldDuck: A rigor di termini, no, non lo fanno. Un compilatore impostato __cplusplussu 199711Lnon è un compilatore C ++ 11 conforme. Probabilmente hanno opzioni per farli comportare correttamente.
Keith Thompson,

39

Come affermato dallo standard C ++ 11 (§iso.16.8):

Il nome __cplusplus è definito al valore 201103L durante la compilazione di un'unità di traduzione C ++.

Con il valore di quella macro, puoi verificare se il compilatore è conforme a C ++ 11.

Ora, se stai cercando un modo standard per verificare se il compilatore supporta un qualsiasi sottoinsieme di funzionalità C ++ 11, penso che non ci sia un modo portabile standard; puoi controllare la documentazione dei compilatori oi file di intestazione della libreria std per ottenere maggiori informazioni.


2
Ad esempio, static_assert è supportato in VS2010 e in tutti i copiler c ++ 11. Quindi, se controlli un valore di __cplusplus maggiore o uguale a quello impostato in VS2010 (cioè> = 199711L), puoi stare bene.
Paolo M

33

So che questa è una domanda molto vecchia, ma questa domanda potrebbe essere vista spesso e le risposte sono un po 'obsolete.

I compilatori più recenti con lo standard C ++ 14 hanno un modo standard per controllare le funzionalità, incluse le funzionalità C ++ 11. Una pagina completa è su https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations

In sintesi, ogni funzionalità ha una macro standard definita che puoi controllare #ifdef. Ad esempio, per verificare i valori letterali definiti dall'utente, è possibile utilizzare

#ifdef __cpp_user_defined_literals

1
Non lo sapevo. Penso che questa semplice funzionalità sia arrivata in ritardo, ma può comunque essere molto utile, soprattutto la __has_include()macro.
prapin

22

Per controllare il supporto C ++ 14 e altri. Test su 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

Puoi usare questo:

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

Per C ++ 11, la maggior parte dei compilatori eccetto Visual Studio imposta la __cplusplusmacro su 201103L, ma qualsiasi versione di Visual Studio la imposta su 199711Lcui è il valore usato per altri compilatori prima di C ++ 11. Questo codice confronta la _cplusplusmacro con 201103Lper tutti i compilatori tranne Visual Studio e, se il compilatore è Visual Studio, controlla se la versione di Visual Studio è successiva alla 2015, la prima versione di Visual Studio che supporta completamente C ++ 11 (per Visual Studio 2015, la _MSC_VERmacro ha il valore 1900, vedi questa risposta ).


1
Questa risposta non è corretta. Perché g++ -std=c++98con GCC 4.8, stampa in modo errato C++11 is supported.
punti

1
@pts Siamo spiacenti, solo un errore di battitura. Dovrebbe essere risolto ora.
Paperino

7

Se non vuoi usare Boost.Config e devi testare i compilatori che supportano C ++ 11, allora il controllo del valore della costante __cplusplusandrà bene. Tuttavia, un compilatore potrebbe supportare la maggior parte delle caratteristiche popolari dello standard C ++ 11 ma non supporta le specifiche complete. Se si desidera abilitare il supporto per compilatori Visual Studio specifici che non sono ancora conformi al 100% alle specifiche C ++ 11, utilizzare il frammento di codice seguente che consente la compilazione in 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

Un elenco completo delle versioni del compilatore per Visual Studio è fornito in Come rilevare se sto compilando codice con Visual Studio 2008


6

Nel tradizionale mondo Linux / Unix, autoconf è tradizionalmente usato per testare la presenza di librerie e funzionalità del compilatore e bug inserendole in un config.h che usi nei tuoi file secondo necessità.


2
Sì, autoconf può essere utilizzato per testare le funzionalità, ma è necessario fargli generare la macro appropriata per errori o successi che possono quindi essere testati dal codice sopra. Quindi di per sé questa risposta non aggiunge alcuna informazione.
Martin York

3
@LokiAstari: non è così che funziona autoconf. Autoconf fornisce macro che consentono allo script di configurazione di compilare un file sorgente di test e impostare #define su 0 o 1 in base al successo della compilazione. La risposta di diverscuba23 fornisce informazioni sottolineando che l'OP sta raggiungendo una soluzione non ottimale al problema reale.
Joseph Garvin


1

Quando si controlla la disponibilità di una libreria C ++ 11 (non una funzionalità del linguaggio), ad esempio l' <array>intestazione, è possibile #if __has_include(<array>).

A volte il controllo #if __cplusplus >= 201103Lti direbbe che usi C ++ 11 ma altre impostazioni come l'impostazione della versione della libreria standard in Xcode potrebbero non avere ancora le nuove librerie disponibili (la maggior parte di esse sono disponibili con nomi diversi cioè <tr1/array>)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.