Есть ли директива препроцессора для обнаружения поддержки С++ 11x?

Если у меня есть код, в котором я хотел бы использовать расширения С++ 11x как можно больше, но иметь запасной вариант, если это не поддерживается. В настоящее время версия GCC для OSX и компилятор VisualC практически не поддерживают C++11x, поэтому я использую:

#if (defined(__APPLE__) || (defined(_WIN32)))
   ...fallback code without C++11x ...
#else
   ... code using C++11x ...
#endif

И это работает, но на самом деле это неправильно, тем более что компилятор gcc в MacPorts ДЕЙСТВИТЕЛЬНО поддерживает c++11x.

Есть ли макрос типа #define C11X_SUPPORTED? Возможно, что-то есть только у GCC?


person Kenneth    schedule 23.05.2012    source источник
comment
Проблема в том, что GCC еще не полностью поддерживает C++11, поэтому все зависит от того, какие функции вы хотите использовать.   -  person juanchopanza    schedule 23.05.2012
comment
ускорит работу: boost.org/doc/libs/1_49_0/libs/config/doc/html/boost_config/ ?   -  person rve    schedule 23.05.2012
comment
@rve: Почему вы не опубликовали это как ответ? Это хороший.   -  person Juraj Blaho    schedule 23.05.2012


Ответы (3)


__cplusplus следует определять как 199711L в компиляторах до C++11 и 201103L в компиляторах, поддерживающих C++11. Является ли это большой помощью на практике, другой вопрос: большинство компиляторов только на полпути, поэтому не следует определять его как 201103L, даже если они поддерживают интересующие вас функции. И компилятор нередко лжет: например, компилятор, который определяет его как 199711L и не поддерживает export для шаблонов. Но нет стандартного функционального теста.

Самое простое решение — просто не использовать какую-либо новую функцию, пока вы не будете уверены, что все компиляторы ее поддерживают. Вы все равно должны написать и поддерживать резервный код; зачем поддерживать две версии. Единственным исключением из этого правила могут быть новые функции, влияющие на производительность: независимо от того, поддерживает ли компилятор семантику перемещения или нет. В таких случаях я бы предложил включаемый файл, зависящий от компилятора, который вы пишете сами на основе документации компилятора и личных тестов; только потому, что компилятор может документально подтвердить, что он поддерживает определенную функцию, не означает, что его поддержка свободна от ошибок. Просто создайте каталог для каждого целевого компилятора, поместите туда этот файл и укажите соответствующую опцию -I или /I в вашем make-файле или файле проекта.

И ваши тесты должны быть чем-то вроде:

#ifdef HAS_MOVE_SEMANTICS
...
#endif

а не только на компиляторе, версии или что-то еще.

person James Kanze    schedule 23.05.2012
comment
Компилятор нередко лжет, а GCC неожиданно говорит правду. Вернее, в некоторых версиях. Примерно до версии 4.7 __cplusplus равно 1, что правильно, поскольку это не полная реализация C++98. Затем он был изменен, чтобы заявить о соответствии в режиме C++98. - person Steve Jessop; 23.05.2012
comment
@SteveJessop g++ никогда не имел полной реализации C++98 или C++03. Он никогда не реализовывал export. Итак, если __cplusplus было 199711L, оно лгало. (Конечно, он далеко не одинок в этой ситуации.) - person James Kanze; 23.05.2012
comment
Вот о чем я говорю, GCC недавно изменили на ложь, тогда как раньше он говорил правду. Причина в том, что было невозможно сказать, говорит ли она правду о том, что C++98 не реализован, или говорит правду о том, что C++11 не реализован. Теперь вы можете различать, где ложь о внедрении C++98, а когда правда о не внедрении C++11. Ура. Я не думаю, что кто-либо когда-либо реализовывал C++98 (или C++03), поэтому точное значение __cplusplus в принципе бесполезно. Это всегда либо зависит от реализации, либо лжет. - person Steve Jessop; 23.05.2012
comment
@SteveJessop В основном это моя точка зрения. Там что-то официально есть, но бесполезно. - person James Kanze; 23.05.2012
comment
Тестирование отдельных функций C++11 превратило бы тестирование в кошмар, потому что (теоретически) нужно тестировать каждую комбинацию поддерживаемых функций. Подход «все или ничего» более практичен, и для этой цели отлично подходит __cplusplus. Если компилятор/библиотека не поддерживает функцию, которую использует код, тогда должна быть ошибка, и тот, кто ее компилирует, должен либо обновить компилятор, либо установить флаги для сборки для более раннего стандарта (при условии, что код поддерживает это). - person hyde; 16.08.2014
comment
@hyde Если все или ничего, то вам нужно полностью исключить C ++ 11, поскольку никто еще не реализовал его полностью. С другой стороны, есть несколько широко реализованных функций, которые весьма полезны, по крайней мере, в некоторых приложениях, и было бы стыдно не использовать их, если они доступны. - person James Kanze; 18.08.2014
comment
@JamesKanze Я не имел в виду, что разработчик должен быть вынужден использовать все функции С++ 11, если компилятор говорит, что это С++ 11 ... Я имел в виду, использовать любое рабочее подмножество функций С++ 11, только если компиляторы говорят, что это C ++11. А если компилятор не полностью поддерживает выбранное подмножество, то приходится использовать C++03 (TR1). Две версии на выбор и необходимые для тестирования: C++11 (с любым его подмножеством, используемым кодом) и C++03 (TR1). - person hyde; 18.08.2014
comment
@hyde Я не совсем понимаю вопрос тестирования; вам нужно протестировать все компиляторы, на которые вы нацелены, даже если условные операторы не задействованы. Кроме того, что касается проблем с синтаксисом, если даже в одном из ваших целевых компиляторов отсутствует эта функция, вы не должны использовать ее где-либо. Потому что, если даже один компилятор его не поддерживает, вам придется поддерживать код, который его не использует. С другой стороны, получение прироста производительности от moveable может быть важно для компиляторов, которые его поддерживают. - person James Kanze; 18.08.2014
comment
@JamesKanze: я бы посчитал export особым случаем, поскольку он также считается исключенным из стандартов C++03/C++98, а затем рассмотрел вопрос о соответствии. Причина в том, что позже она была отброшена как плохая идея, и я думаю, что была только одна реализация, поддерживающая ее, или около того. И я не уверен, насколько хорошо. - person Deduplicator; 16.01.2015
comment
@Deduplicator Моя точка зрения была больше о достоверности проверки. export явно был частью (и важной частью) C++98. Однако большинство компиляторов прошли стадию, когда они заявили о полном соответствии, но не реализовали export. Другими словами, вы не можете проверить все или ничего; вам действительно нужна отдельная проверка функций, определенная уникально для каждого компилятора. - person James Kanze; 17.01.2015
comment
Как использовать то же самое для С++ 14? - person fnc12; 06.08.2016

Вы можете проверить значение макроса __cplusplus. Для C++11 это больше, чем 199711L.

Так что-то вроде

#if __cplusplus > 199711L

#endif
person Luchian Grigore    schedule 23.05.2012
comment
с оговоркой, что пока нет полной поддержки. - person juanchopanza; 23.05.2012
comment
@juanchopanza да, это никоим образом не гарантирует полной поддержки С++ 11 или того, что компилятор вообще поддерживает С++ 11 (но, вероятно, это лучшее, что вы можете получить). - person Luchian Grigore; 23.05.2012
comment
Также с оговоркой, что компиляторы, как известно, лгут. - person James Kanze; 23.05.2012
comment
К сожалению, это не работает на MSVC даже в 2021 году. - person Dwedit; 01.02.2021

Библиотека Boost.Config предоставляет детальные макросы препроцессора, которые можно использовать для условной компиляции на основе наличия заданного Функция С++11.

(Для компилятора поддержка C++11 не обязательно должна быть предложением «все или ничего». Например, рассмотрим, как Microsoft cherry выбрали, какие функции C++11 включить в Visual Studio 2012, исходя из того, что, по их мнению, принесет наибольшую пользу их клиентам.)

person Edward Brey    schedule 21.05.2013