¿Cómo verifico la compatibilidad con C ++ 11?

104

¿Hay alguna forma de detectar en tiempo de compilación si el compilador es compatible con ciertas características de C ++ 11? Por ejemplo, algo como esto:

#ifndef VARIADIC_TEMPLATES_SUPPORTED

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

#else

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

#endif
Maxpm
fuente
2
Podría tener un encabezado llamado "assert_variadic_template_support.hpp" que puede incluir y hacer algo como template <typename... Test> struct compiler_must_support_variadic_templates;. Un error de sintaxis revelaría rápidamente el problema. (Solo como acotación al margen, un mensaje de error adecuado es mucho mejor.)
GManNickG
La forma "correcta" de resolver este problema es una prueba de configuración.
Joseph Garvin

Respuestas:

125

Hay una constante denominada __cplusplusque los compiladores de C ++ deben establecer en la versión del estándar C ++ compatible; consulte esto

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

Está configurado en 199711L en Visual Studio 2010 SP1, pero no sé si los proveedores serán tan audaces para aumentarlo ya si solo tienen soporte (parcial) a nivel de compilador en comparación con una biblioteca C ++ estándar con todos los cambios de C ++ 11 .

Por lo tanto, las definiciones de Boost mencionadas en otra respuesta siguen siendo la única forma sensata de averiguar si hay, por ejemplo, soporte para subprocesos C ++ 11 y otras partes específicas del estándar.

Cygon
fuente
37
C ++ 11 establece el valor de __cplusplusen 201103L. Eso afirma la plena conformidad con el estándar de 2011; no le informa acerca de la conformidad parcial o las extensiones del compilador. Si __cplusplusse establece en 201103L, entonces el compilador se ajusta completamente o te está mintiendo. Si no es así, no se puede saber qué funciones admite.
Keith Thompson
1
g ++ 4.7.x (y presumiblemente más reciente) establece esto cuando -std=c++11se especifica la opción (puede que también con -std=gnu++11). Lo hacen, aunque no están del todo completas en funciones (4.8 nos acerca mucho más). Nota: existe una brecha entre lo que admite el compilador y lo que está disponible en la biblioteca estándar. Tanto 4.7.xy 4.8.x carecen actualmente de compatibilidad con expresiones regulares, pero esa es una biblioteca, no una característica del compilador.
Nathan Ernst
1
Me pregunto por qué esta no es la respuesta aceptada. Además, puede utilizar esta sugerencia para mejorar aún más su respuesta, es muy buena.
Iharob Al Asimi
1
@KeithThompson Para mí, tanto Code :: Blocks como Visual Studio establecen el valor de __cplusplusto 199711Lpara C ++ 11.
Donald Duck
3
@DonaldDuck: Estrictamente hablando, no, no es así. Un compilador que se establece __cplusplusen 199711Lno es un compilador conforme a C ++ 11. Probablemente tengan opciones para que se comporten correctamente.
Keith Thompson
39

Según lo establecido por el estándar C ++ 11 (§iso.16.8):

El nombre __cplusplus se define con el valor 201103L al compilar una unidad de traducción de C ++.

Con el valor de esa macro, puede verificar si el compilador es compatible con C ++ 11.

Ahora, si está buscando una forma estándar de verificar si el compilador admite un subconjunto de características de C ++ 11, creo que no existe una forma estándar y portátil; puede consultar la documentación de los compiladores o los archivos de encabezado de la biblioteca estándar para obtener más información.

Paolo M
fuente
2
Por ejemplo, static_assert se admite en VS2010 y en todos los copilers de c ++ 11. Por lo tanto, si busca un valor de __cplusplus mayor o igual que el establecido en VS2010 (es decir,> = 199711L), puede estar bien.
Paolo M
33

Sé que esta es una pregunta muy antigua, pero es posible que se vea con frecuencia y las respuestas estén un poco desactualizadas.

Los compiladores más nuevos con el estándar C ++ 14 tienen una forma estándar de verificar características, incluidas las características de C ++ 11. Hay una página completa en https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations

En resumen, cada función tiene una macro estándar definida con la que puede verificar #ifdef. Por ejemplo, para comprobar los literales definidos por el usuario, puede utilizar

#ifdef __cpp_user_defined_literals
Jarryd
fuente
1
Yo no lo sabía. Creo que esta simple característica llega tarde, pero aún puede ser muy útil, especialmente la __has_include()macro.
prapin
22

Para comprobar el soporte C ++ 14 y otros. Pruebas en 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
fuente
17

Puedes usar esto:

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

Para C ++ 11, la mayoría de los compiladores, excepto Visual Studio, establecen la __cplusplusmacro en 201103L, pero cualquier versión de Visual Studio la establece en, 199711Lque es el valor utilizado para otros compiladores antes de C ++ 11. Este código compara la _cplusplusmacro con 201103Ltodos los compiladores excepto Visual Studio, y si el compilador es Visual Studio, verifica si la versión de Visual Studio es posterior a 2015, la primera versión de Visual Studio que es completamente compatible con C ++ 11 (para Visual Studio 2015, la _MSC_VERmacro tiene el valor 1900, consulte esta respuesta ).

Pato Donald
fuente
1
Esta respuesta es incorrecta. Porque g++ -std=c++98con GCC 4.8, imprime incorrectamente C++11 is supported.
pts
1
@pts Lo siento, solo un error tipográfico. Debería arreglarse ahora.
Donald Duck
7

Si no desea utilizar Boost.Config y necesita probar compiladores que admitan C ++ 11, entonces comprobar el valor de la constante __cplusplusserá suficiente. Sin embargo, un compilador puede admitir la mayoría de las funciones populares del estándar C ++ 11, pero no admite todas las especificaciones. Si desea habilitar la compatibilidad con compiladores de Visual Studio específicos que aún no cumplen al 100% con las especificaciones de C ++ 11, utilice el siguiente fragmento de código que permite compilar en 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

Se proporciona una lista completa de versiones del compilador para Visual Studio en Cómo detectar si estoy compilando código con Visual Studio 2008

Vamshi Krishna
fuente
6

En el mundo tradicional de Linux / Unix, autoconf se usa tradicionalmente para probar la presencia de bibliotecas y características del compilador y errores colocándolos en un config.h que usa en sus archivos según sea necesario.

diverscuba23
fuente
2
Sí, autoconf se puede usar para probar las características, pero debe hacer que genere la macro adecuada para fallas o éxitos que luego se pueden probar con el código anterior. Entonces, por sí misma, esta respuesta no agrega información.
Martin York
3
@LokiAstari: No es así como funciona autoconf. Autoconf proporciona macros que le permiten hacer que su script configure compile un archivo fuente de prueba y establezca #define en 0 o 1 en función del éxito de la compilación. La respuesta de diverscuba23 proporciona información al señalar que el OP está buscando una solución subóptima para el problema real.
Joseph Garvin
1

Cuando su cheque es para la disponibilidad de una biblioteca de C ++ 11 (no una característica de idioma), por ejemplo, el <array>encabezado, puede#if __has_include(<array>) .

A veces, la verificación #if __cplusplus >= 201103Lle indicaría que usa C ++ 11, pero es posible que otras configuraciones como la configuración de la versión de biblioteca estándar en Xcode aún no tengan las nuevas bibliotecas disponibles (la mayoría de ellas están disponibles con diferentes nombres, es decir <tr1/array>)

yairchu
fuente