Como verifico o suporte para C ++ 11?

104

Existe uma maneira de detectar em tempo de compilação se o compilador oferece suporte a determinados recursos do C ++ 11? Por exemplo, algo assim:

#ifndef VARIADIC_TEMPLATES_SUPPORTED

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

#else

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

#endif
Maxpm
fonte
2
Você poderia ter um cabeçalho chamado "assert_variadic_template_support.hpp" que você pode incluir e dentro de fazer algo semelhante template <typename... Test> struct compiler_must_support_variadic_templates;. Um erro de sintaxe revelaria rapidamente o problema. (Como um aparte, uma mensagem de erro adequada é muito melhor.)
GManNickG
A maneira 'certa' de resolver este problema é um teste de configuração.
Joseph Garvin

Respostas:

125

Há uma constante chamada __cplusplusque os compiladores C ++ devem definir para a versão do padrão C ++ compatível, consulte isto

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

Ele está definido como 199711L no Visual Studio 2010 SP1, mas não sei se os fornecedores serão tão ousados ​​em aumentá-lo se eles apenas tiverem suporte (parcial) no nível do compilador versus uma biblioteca C ++ padrão com todas as alterações do C ++ 11 .

Portanto, as definições de Boost mencionadas em outra resposta continuam sendo a única maneira sensata de descobrir se há, por exemplo, suporte para threads C ++ 11 e outras partes específicas do padrão.

Cygon
fonte
37
C ++ 11 define o valor de __cpluspluspara 201103L. Isso afirma total conformidade com o padrão de 2011; não fala sobre conformidade parcial ou extensões do compilador. Se __cplusplusestiver definido como 201103L, o compilador está totalmente em conformidade ou ele está mentindo para você. Se não for, você não saberá quais recursos ele oferece suporte.
Keith Thompson
1
g ++ 4.7.x (e presumivelmente mais recente) define isso quando a -std=c++11opção é especificada (também pode com -std=gnu++11). Eles fazem isso, embora não sejam totalmente completos (4.8 nos aproxima muito). Nota - há uma lacuna entre o que o compilador suporta e o que está disponível na biblioteca padrão. Ambos 4.7.x e 4.8.x não têm suporte regex - mas isso é uma biblioteca, não um recurso de compilador.
Nathan Ernst
1
Eu me pergunto por que essa não é a resposta aceita. Além disso, você pode usar esta sugestão para melhorar ainda mais sua resposta, é muito bom.
Iharob Al Asimi
1
@KeithThompson Para mim, ambos Code :: Blocks e Visual Studio definiram o valor de __cpluspluspara 199711Lpara C ++ 11.
Pato Donald
3
@DonaldDuck: Estritamente falando, não, eles não querem. Um compilador definido __cpluspluscomo 199711Lnão é um compilador C ++ 11 em conformidade. Eles provavelmente têm opções para fazê-los se comportar corretamente.
Keith Thompson
39

Conforme declarado pelo padrão C ++ 11 (§iso.16.8):

O nome __cplusplus é definido com o valor 201103L ao compilar uma unidade de tradução C ++.

Com o valor dessa macro, você pode verificar se o compilador é compatível com C ++ 11.

Agora, se você está procurando uma maneira padrão de verificar se o compilador oferece suporte a algum subconjunto de recursos do C ++ 11, acho que não existe uma maneira portátil padrão; você pode verificar a documentação dos compiladores ou arquivos de cabeçalho da biblioteca std para obter mais informações.

Paolo M
fonte
2
Por exemplo, static_assert é compatível com VS2010 e em todos os copiladores c ++ 11. Portanto, se você verificar um valor de __cplusplus maior ou igual ao definido em VS2010 (ou seja,> = 199711L), você pode estar bem.
Paolo M,
33

Eu sei que esta é uma pergunta muito antiga, mas ela pode ser vista com frequência e as respostas estão um pouco desatualizadas.

Compiladores mais novos com o padrão C ++ 14 têm uma maneira padrão de verificar recursos, incluindo recursos do C ++ 11. Uma página abrangente está em https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations

Em resumo, cada recurso possui uma macro padrão definida com a qual você pode verificar #ifdef. Por exemplo, para verificar literais definidos pelo usuário, você pode usar

#ifdef __cpp_user_defined_literals
Jarryd
fonte
1
Eu não sabia disso. Acho que esse recurso simples está chegando tarde, mas ainda pode ser muito útil, especialmente a __has_include()macro.
prapin
22

Para verificar o suporte C ++ 14 e outros. Testando no 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
fonte
17

Você pode usar isto:

#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, a maioria dos compiladores, exceto Visual Studio, define a __cplusplusmacro como 201103L, mas qualquer versão do Visual Studio a define como, 199711Lque é o valor usado para outros compiladores antes de C ++ 11. Este código compara a _cplusplusmacro com 201103Ltodos os compiladores, exceto Visual Studio, e se o compilador for Visual Studio, ele verifica se a versão do Visual Studio é posterior a 2015, a primeira versão do Visual Studio que oferece suporte total a C ++ 11 (para Visual Studio 2015, a _MSC_VERmacro tem o valor 1900, veja esta resposta ).

Pato Donald
fonte
1
Esta resposta está incorreta. Com o g++ -std=c++98GCC 4.8, ele imprime incorretamente C++11 is supported.
pontos
1
@pts Desculpe, apenas um erro de digitação. Deve ser consertado agora.
Pato Donald
7

Se você não quiser usar Boost.Config e precisar testar os compiladores que suportam C ++ 11, verificar o valor da constante __cplusplusserá suficiente . No entanto, um compilador pode oferecer suporte à maioria dos recursos populares do padrão C ++ 11, mas não oferece suporte a todas as especificações. Se você deseja ativar o suporte para compiladores específicos do Visual Studio que ainda não são 100% compatíveis com as especificações do C ++ 11, use o seguinte snippet de código que permite a compilação no 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

Uma lista completa de versões do compilador para Visual Studio é fornecida em Como detectar se estou compilando código com o Visual Studio 2008

Vamshi Krishna
fonte
6

No mundo Linux / Unix tradicional, o autoconf é tradicionalmente usado para testar a presença de bibliotecas e recursos de compilador e bugs, colocando-os em um config.h que você usa em seus arquivos conforme necessário.

diverscuba23
fonte
2
Sim, o autoconf pode ser usado para testar recursos, mas você deve fazê-lo gerar a macro apropriada para falhas ou sucessos que podem ser testados pelo código acima. Portanto, por si só, essa resposta não adiciona nenhuma informação.
Martin York
3
@LokiAstari: Não é assim que o autoconf funciona. O Autoconf fornece macros que permitem que você faça com que seu script de configuração compile um arquivo de origem de teste e defina #define como 0 ou 1 com base no sucesso da compilação. A resposta de diverscuba23 fornece informações ao apontar que o OP está chegando a uma solução abaixo do ideal para o problema real.
Joseph Garvin
1

Quando sua verificação for para a disponibilidade de uma biblioteca C ++ 11 (não um recurso de linguagem), por exemplo, o <array>cabeçalho, você pode #if __has_include(<array>).

Às vezes, a verificação #if __cplusplus >= 201103Ldiria que você usa C ++ 11, mas outras configurações, como a configuração da versão da biblioteca padrão no Xcode, podem ainda não ter as novas bibliotecas disponíveis (a maioria delas estão disponíveis em nomes diferentes, por exemplo <tr1/array>)

Yairchu
fonte