Как проверить поддержку C ++ 11?

104

Есть ли способ определить во время компиляции, поддерживает ли компилятор определенные функции C ++ 11? Например, примерно так:

#ifndef VARIADIC_TEMPLATES_SUPPORTED

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

#else

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

#endif
Макс.
источник
2
У вас может быть заголовок под названием «assert_variadic_template_support.hpp», который вы можете включить и внутри сделать что-то вроде template <typename... Test> struct compiler_must_support_variadic_templates;. Синтаксическая ошибка быстро выявит проблему. (
Кстати
«Правильный» способ решить эту проблему - это проверка конфигурации.
Джозеф Гарвин

Ответы:

125

Существует константа с именем, __cplusplusкоторую компиляторы C ++ должны установить для версии поддерживаемого стандарта C ++, см. Это

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

В Visual Studio 2010 с пакетом обновления 1 (SP1) для него установлено значение 199711L, но я не знаю, будут ли поставщики настолько смелыми, чтобы уже увеличивать его, если у них просто (частичная) поддержка уровня компилятора по сравнению со стандартной библиотекой C ++ со всеми изменениями C ++ 11. .

Таким образом, определения Boost, упомянутые в другом ответе, остаются единственным разумным способом выяснить, есть ли, например, поддержка потоков C ++ 11 и других конкретных частей стандарта.

Cygon
источник
37
C ++ 11 устанавливает значение __cplusplusв 201103L. Это подтверждает полное соответствие стандарту 2011 года; он не говорит вам о частичном соответствии или расширениях компилятора. Если __cplusplusустановлено значение 201103L, то либо компилятор полностью соответствует требованиям, либо он вам лжет. Если это не так, то вы не сможете точно сказать, какие функции он поддерживает.
Кейт Томпсон
1
g ++ 4.7.x (и предположительно новее) устанавливает это, когда -std=c++11указана опция (также может быть -std=gnu++11). Они делают это, даже если они не совсем полнофункциональные (4.8 делает нас намного ближе). Обратите внимание: существует разрыв между тем, что поддерживает компилятор, и тем, что доступно в стандартной библиотеке. В 4.7.x и 4.8.x в настоящее время отсутствует поддержка регулярных выражений, но это библиотека, а не функция компилятора.
Натан Эрнст
1
Интересно, почему это не принятый ответ. Кроме того, вы можете использовать это предложение, чтобы улучшить свой ответ, это очень хорошо.
Iharob Al Asimi 04
1
@KeithThompson Для меня, как Code :: Blocks и Visual Studio установите значение __cplusplusдля 199711Lдля C ++ 11.
Donald Duck
3
@DonaldDuck: Строго говоря, нет. Компилятор, __cplusplusдля 199711Lкоторого установлено значение, не соответствует компилятору C ++ 11. У них, вероятно, есть варианты, чтобы заставить их вести себя правильно.
Кейт Томпсон
39

Как указано в стандарте C ++ 11 (§iso.16.8):

Имя __cplusplus определяется значением 201103L при компиляции единицы перевода C ++.

С помощью значения этого макроса вы можете проверить, соответствует ли компилятор C ++ 11.

Теперь, если вы ищете стандартный способ проверить, поддерживает ли компилятор какое-либо подмножество функций C ++ 11, я думаю, что нет стандартного переносимого способа; вы можете проверить документацию компилятора или заголовочные файлы библиотеки std, чтобы получить дополнительную информацию.

Паоло М
источник
2
Например, static_assert поддерживается в VS2010 и во всех копилерах C ++ 11. Итак, если вы проверите значение __cplusplus, большее или равное значению, установленному в VS2010 (т.е.> = 199711L), все будет в порядке.
Paolo M
33

Я знаю, что это очень старый вопрос, но этот вопрос можно часто встретить, и ответы на него немного устарели.

Новые компиляторы со стандартом C ++ 14 имеют стандартный способ проверки функций, включая функции C ++ 11. Подробная страница находится по адресу https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations.

Таким образом, для каждой функции определен стандартный макрос, с которым вы можете проверить #ifdef. Например, чтобы проверить определенные пользователем литералы, вы можете использовать

#ifdef __cpp_user_defined_literals
Джаррид
источник
1
Я этого не знал. Я думаю, что эта простая функция появится поздно, но все же может быть очень полезной, особенно __has_include()макрос.
prapin
22

Для проверки поддержки C ++ 14 и прочего. Тестирование на 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;
}
куроно267
источник
17

Вы можете использовать это:

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

Для C ++ 11 большинство компиляторов, за исключением Visual Studio, устанавливают __cplusplusмакрос в значение 201103L, но любая версия Visual Studio устанавливает его в 199711Lзначение, которое использовалось для других компиляторов до C ++ 11. Этот код сравнивает _cplusplusмакрос со 201103Lвсеми компиляторами, кроме Visual Studio, и если это Visual Studio, он проверяет, является ли версия Visual Studio более поздней, чем 2015, первая версия Visual Studio, которая полностью поддерживает C ++ 11 (для Visual Studio Studio 2015, _MSC_VERмакрос имеет значение 1900, см. Этот ответ ).

Дональд Дак
источник
1
Это неверный ответ. Поскольку g++ -std=c++98с GCC 4.8 он неправильно печатает C++11 is supported.
Очков
1
@pts Извините, только опечатка. Это должно быть исправлено сейчас.
Дональд Дак
7

Если вы не хотите использовать Boost.Config и вам нужно протестировать компиляторы, поддерживающие C ++ 11, тогда __cplusplusподойдет проверка значения константы . Однако компилятор может поддерживать большинство популярных функций стандарта C ++ 11, но не поддерживает все спецификации. Если вы хотите включить поддержку определенных компиляторов Visual Studio, которые еще не на 100% соответствуют спецификациям C ++ 11, используйте следующий фрагмент кода, который позволяет компилировать в 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

Полный список версий компилятора для Visual Studio приведен в разделе Как определить, компилирую ли я код с помощью Visual Studio 2008.

Вамши Кришна
источник
6

В традиционном мире Linux / Unix autoconf традиционно используется для проверки наличия библиотек и функций компилятора и размещения ошибок в config.h, который вы используете в своих файлах по мере необходимости.

diverscuba23
источник
2
Да, autoconf можно использовать для тестирования функций, но вы должны заставить его генерировать соответствующий макрос для сбоя или успеха, который затем можно проверить с помощью приведенного выше кода. Так что сам по себе этот ответ не добавляет информации.
Мартин Йорк
3
@LokiAstari: Autoconf работает не так. Autoconf предоставляет макросы, которые позволяют вашему скрипту configure скомпилировать тестовый исходный файл и установить для #define значение 0 или 1 в зависимости от успеха компиляции. Ответ diverscuba23 предоставляет информацию, указывая на то, что OP пытается найти неоптимальное решение реальной проблемы.
Джозеф Гарвин
1

Если ваша проверка касается наличия библиотеки C ++ 11 (не языковой функции), например <array>заголовка, вы можете #if __has_include(<array>).

Иногда проверка #if __cplusplus >= 201103Lможет сказать вам, что вы используете C ++ 11, но другие настройки, такие как настройка версии стандартной библиотеки в Xcode, могут по-прежнему не иметь доступных новых библиотек (большинство из них доступны под разными именами, т.е. <tr1/array>)

Яирчу
источник