__cplusplus в разных компиляторах

Макрос __cplusplus изначально создавался для предоставления программистам возможности определения факта использования компилятора С++. Это было нужно для создания кода, который мог бы компилироваться как «новыми» (на то время) компиляторами С++, так и старыми для языка С. В частности он используется для отключения украшения имён (если нужно).

#if defined __cplusplus
extern "C" {
#endif

int foo();

#if defined __cplusplus
}
#endif

Со временем, по мере развития языка С++, макрос __cplusplus стал использоваться для указания стандарта, реализуемого компилятором. Там же, в стандартах (как правило, п. 16.8.1), указывались и значения, которые должен возвращать этот макрос для того или иного стандарта. Они приведены в таблице ниже.

Стандарт __cplusplus
до C+++98 1
C++98 199711L
C++11 201103L
C++14 201402L
C++17 201703L

Такой подход стал использоваться для написания кода, компилируемого как новыми, так и старыми версиями компиляторов, не поддерживающими новые стандарты.

В теории все красиво и замечательно. Но, практика как всегда показывает свое суровое лицо. Проблема в том, что далеко не все компиляторы следуют этим правилам и возвращают нужное значение __cplusplus. Ниже приводится несколько таких примеров.

gcc версии 5.4 (и некоторых других, судя по сообщениям на тематических форумах) для стандарта С++17 возвращают __cplusplus равным 201500L. Скорее всего это связано с еще не полной поддержкой этого стандарта в данной версии компилятора. Подтверждает эту версию тот факт, что gcc версии 8.1.0 (проверялась Windows-версия) для этого стандарта возвращает правильное значение.

В данном случае gcc, на мой взгляд, ведет себя абсолютно правильно. Число 201500L больше значения __cplusplus для С++14, тем самым gcc как бы говорит: «я реализую более новый функционал языка по сравнению со стандартом С++14». С другой стороны, если gcc на текущей стадии разработки реализует не полный набор новых возможностей С++17, или же они не до конца протестированы, он не может возвращать значение 201703L. Если он его вернет, то разработчик, уверовав в полную поддержку стандарта, станет его использовать, и будет очень удивлен, обнаружив, что поведение написанного им кода отличается от того, что обещается стандартом.

Таким образом, gcc не может вернуть 201402L, так как реализует более новое поведение по сравнению со стандартом С++14. И одновременно с этим не может вернуть 201703L, так как еще не полностью реализует этот стандарт. Значение 201500L является «золотой серединой».

К сожалению не все компиляторы так заботятся о программистах, которые ими пользуются.

Компилятор, входящий в состав Microsoft Visual Studio 2017 возвращает __cplusplus равным 199711L и при использовании С++14, и при использовании С++17. Об этом говорится и на форуме. Объяснить такое поведение неполной реализацией стандарта никак нельзя. Возвращаемое значение 199711L соответствует стандарту С++98. Я просто не верю в то, что в Microsoft Visual Studio 2017 нет поддержки стандарта С++11 (хотя бы). Да и потом зачем тогда нужны ключи компиляции под новые стандарты, если они все равно не реализуются.

При таком подходе у разработчиков просто нет надежных средств для определения используемого стандарта. И как в таких условиях писать переносимый код? Нет, я конечно понимаю, что Microsoft хочет всех посадить на свою среду и чтобы никто с нее не ушел. Но нам оно надо? Лично мне — нет.

Похожим образом поступают и в компании Embarcadero. Причем там это делают еще более нагло. Если в случае с Microsoft это как-то списывают на баг, то в случае с Embarcadero это никак не баг, а умышленный осознанный шаг. Достаточно заглянуть в документацию (по ссылке ). В ней прямо указано, что __cplusplus возвращает единицу. То есть мы вернулись на несколько десятилетий назад к первоначальному значению __cplusplus. А как же стандарты? (Какие стандарты?)

Получается, что из всех трех рассмотренных компиляторов только gcc соблюдает стандарты языка С++. Разумеется, здесь рассматривалось только значение макроса __cplusplus. Это никак нельзя считать критерием полного (не)соответствия стандарту. Но даже это позволяет сделать определенные выводы…

Один ответ

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *