Comment vérifier la prise en charge de C ++ 11?

104

Existe-t-il un moyen de détecter au moment de la compilation si le compilateur prend en charge certaines fonctionnalités de C ++ 11? Par exemple, quelque chose comme ceci:

#ifndef VARIADIC_TEMPLATES_SUPPORTED

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

#else

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

#endif
Maxpm
la source
2
Vous pourriez avoir un en-tête appelé "assert_variadic_template_support.hpp" que vous pouvez inclure et faire quelque chose comme template <typename... Test> struct compiler_must_support_variadic_templates;. Une erreur de syntaxe révélerait rapidement le problème. (En
passant
La «bonne» façon de résoudre ce problème est un test de configuration.
Joseph Garvin

Réponses:

125

Il existe une constante nommée __cplusplusque les compilateurs C ++ doivent définir sur la version de la norme C ++ prise en charge voir ceci

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

Il est défini sur 199711L dans Visual Studio 2010 SP1, mais je ne sais pas si les fournisseurs seront si audacieux pour l'augmenter déjà s'ils ont juste une prise en charge (partielle) au niveau du compilateur par rapport à une bibliothèque C ++ standard avec toutes les modifications C ++ 11 .

Les définitions de Boost mentionnées dans une autre réponse restent donc le seul moyen sensé de déterminer s'il existe, par exemple, un support pour les threads C ++ 11 et d'autres parties spécifiques de la norme.

Cygone
la source
37
C ++ 11 définit la valeur de __cplusplusà 201103L. Cela affirme la pleine conformité à la norme 2011; il ne vous informe pas sur la conformité partielle ou les extensions du compilateur. Si __cplusplusest défini sur 201103L, alors soit le compilateur est entièrement conforme, soit il vous ment. Si ce n'est pas le cas, vous ne pouvez pas vraiment dire quelles fonctionnalités il prend en charge.
Keith Thompson
1
g ++ 4.7.x (et probablement plus récent) définit ceci lorsque l' -std=c++11option est spécifiée (peut également avec -std=gnu++11). Ils font cela, même s'ils ne sont pas tout à fait complets (4.8 nous rapproche beaucoup). Remarque - il existe un écart entre ce que le compilateur prend en charge et ce qui est disponible dans la bibliothèque standard. Les versions 4.7.x et 4.8.x ne prennent actuellement pas en charge les regex - mais c'est une bibliothèque, pas une fonctionnalité de compilateur.
Nathan Ernst
1
Je me demande pourquoi ce n'est pas la réponse acceptée. Aussi, vous pouvez utiliser cette suggestion pour améliorer encore votre réponse, c'est très bien.
Iharob Al Asimi
1
@KeithThompson Pour moi, Code :: Blocks et Visual Studio définissent la valeur de __cplusplussur 199711Lpour C ++ 11.
Donald Duck
3
@DonaldDuck: À proprement parler, non, ils ne le font pas. Un compilateur défini __cplusplussur 199711Ln'est pas un compilateur C ++ 11 conforme. Ils ont probablement des options pour les faire se comporter correctement.
Keith Thompson
39

Comme indiqué par la norme C ++ 11 (§iso.16.8):

Le nom __cplusplus est défini sur la valeur 201103L lors de la compilation d'une unité de traduction C ++.

Avec la valeur de cette macro, vous pouvez vérifier si le compilateur est compatible C ++ 11.

Maintenant, si vous cherchez un moyen standard de vérifier si le compilateur prend en charge un sous-ensemble quelconque de fonctionnalités C ++ 11, je pense qu'il n'y a pas de moyen portable standard; vous pouvez consulter la documentation des compilateurs ou les fichiers d'en-tête de la bibliothèque std pour obtenir plus d'informations.

Paolo M
la source
2
Par exemple, static_assert est pris en charge dans VS2010 et dans tous les copilateurs c ++ 11. Donc, si vous vérifiez une valeur de __cplusplus supérieure ou égale à celle définie dans VS2010 (c'est-à-dire> = 199711L), tout peut bien se passer.
Paolo M
33

Je sais que c'est une question très ancienne, mais cette question pourrait être souvent vue, et les réponses sont un peu dépassées.

Les nouveaux compilateurs avec la norme C ++ 14 ont un moyen standard de vérifier les fonctionnalités, y compris les fonctionnalités C ++ 11. Une page complète est à https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations

En résumé, chaque fonctionnalité a une macro standard définie que vous pouvez vérifier #ifdef. Par exemple, pour rechercher des littéraux définis par l'utilisateur, vous pouvez utiliser

#ifdef __cpp_user_defined_literals
Jarryd
la source
1
Je ne savais pas ça. Je pense que cette fonctionnalité simple arrive en retard, mais peut encore être très utile, en particulier la __has_include()macro.
prapin le
22

Pour vérifier le support C ++ 14 et autres. Test sur 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
la source
17

Vous pouvez utiliser ceci:

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

Pour C ++ 11, la plupart des compilateurs, à l'exception de Visual Studio, définissent la __cplusplusmacro sur 201103L, mais toute version de Visual Studio la définit à 199711Lquelle valeur est utilisée pour les autres compilateurs avant C ++ 11. Ce code compare la _cplusplusmacro avec 201103Lpour tous les compilateurs sauf Visual Studio, et si le compilateur est Visual Studio, il vérifie si la version de Visual Studio est postérieure à 2015, la première version de Visual Studio qui prend complètement en charge C ++ 11 (pour Visual Studio 2015, la _MSC_VERmacro a la valeur 1900, voir cette réponse ).

Donald Duck
la source
1
Cette réponse est incorrecte. Car g++ -std=c++98avec GCC 4.8, il s'imprime incorrectement C++11 is supported.
pts
1
@pts Désolé, juste une faute de frappe. Cela devrait être corrigé maintenant.
Donald Duck
7

Si vous ne souhaitez pas utiliser Boost.Config et devez tester des compilateurs prenant en charge C ++ 11, alors la vérification de la valeur de la constante __cplusplusfera l'affaire. Cependant, un compilateur peut prendre en charge la plupart des fonctionnalités populaires de la norme C ++ 11, mais il ne prend pas en charge toutes les spécifications. Si vous souhaitez activer la prise en charge de compilateurs Visual Studio spécifiques qui ne sont pas encore 100% conformes aux spécifications C ++ 11, utilisez l'extrait de code suivant qui permet la compilation dans 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

Une liste complète des versions du compilateur pour Visual Studio est fournie sur Comment détecter si je compile du code avec Visual Studio 2008

Vamshi Krishna
la source
6

Dans le monde Linux / Unix traditionnel, autoconf est traditionnellement utilisé pour tester la présence de bibliothèques et de fonctionnalités de compilateur et les bogues en les plaçant dans un fichier config.h que vous utilisez dans vos fichiers si nécessaire.

diverscuba23
la source
2
Oui, autoconf peut être utilisé pour tester des fonctionnalités, mais vous devez lui faire générer la macro appropriée en cas d'échec ou de succès qui peut ensuite être testée par le code ci-dessus. Donc, à elle seule, cette réponse n'ajoute aucune information.
Martin York
3
@LokiAstari: Ce n'est pas ainsi que fonctionne l'autoconf. Autoconf fournit des macros qui vous permettent de demander à votre script de configuration de compiler un fichier source de test et de définir #define sur 0 ou 1 en fonction du succès de la compilation. La réponse de diverscuba23 fournit des informations en soulignant que le PO cherche une solution sous-optimale au problème réel.
Joseph Garvin
1

Lorsque votre vérification porte sur la disponibilité d'une bibliothèque C ++ 11 (pas une fonctionnalité de langage), par exemple l'en- <array>tête, vous pouvez#if __has_include(<array>) .

Parfois, la vérification #if __cplusplus >= 201103Lvous dirait que vous utilisez C ++ 11 mais d'autres paramètres comme le paramètre de version de bibliothèque standard dans Xcode peuvent ne pas avoir les nouvelles bibliothèques disponibles (la plupart d'entre elles sont disponibles sous des noms différents, par exemple <tr1/array>)

Yairchu
la source