2013-03-24 1 views
3

Новые версии Clang поддерживают некоторые расширения C++ 11 при компиляции в режиме C++ 03, но могут выдавать предупреждение с включенным -Wc++11-extensions. Например, составление этого кода:Какие расширения C++ 11 поддерживают Clang в режиме C++ 03?

std::map<int, int> foo; 
for(auto &i : foo) { 
} 

с clang test.cpp -std=c++03 результатов этих предупреждений:

test.cpp:5:6: warning: 'auto' type specifier is a C++11 extension 
     [-Wc++11-extensions] 
     for(auto &i : foo) { 
      ^
test.cpp:5:14: warning: range-based for loop is a C++11 extension 
     [-Wc++11-extensions] 
     for(auto &i : foo) { 

но компиляция завершается успешно и правильный код генерируется. Однако, пытаясь использовать, например, равномерная инициализация (std::map<int, int> foo{{1,2},{3,4}};) терпит неудачу с синтаксической ошибкой.

В моем случае у меня есть существующая, неизменяемая библиотека, которая только компилируется в режиме C++ 03 из-за некоторых проблем совместимости; разработчики заявили, что будут поддерживать C++ 11 в ближайшем будущем. Я хочу написать код с этой библиотекой, используя возможности C++ 11, поэтому мне не нужно возвращаться и «модернизировать» код еще раз, когда они делают свою библиотеку совместимой с C++ 11. Расширения Clang C++ 11 кажутся идеальными для этой цели, но я не уверен, что я могу использовать. Расширяются ли расширения Clang C++ 11 где-то?

ответ

7

Есть два «функция-тест» макросы, которые вы можете поместить использовать здесь:

__has_feature и __has_extension

Эти функции, как макросы с одним аргументом идентификатор, имя функции. __has_feature оценивает 1, если эта функция поддерживается Clang и стандартизирована в текущем стандарте языка или 0, если нет, тогда как __has_extension оценивает 1, если эта функция поддерживается Clang на текущем языке (либо в качестве расширения языка, либо на стандартном языке функция) или 0, если нет.

Эти макросы и идентификаторы описаны здесь:

http://clang.llvm.org/docs/LanguageExtensions.html

В вашем конкретном примере, следующий HelloWorld является наиболее информативным:

#if __has_extension(cxx_generalized_initializers) 
#warning __has_extension(cxx_generalized_initializers) is true 
#else 
#warning __has_extension(cxx_generalized_initializers) is false 
#endif 

#if __has_feature(cxx_generalized_initializers) 
#warning __has_feature(cxx_generalized_initializers) is true 
#else 
#warning __has_feature(cxx_generalized_initializers) is false 
#endif 

#if __has_extension(cxx_range_for) 
#warning __has_extension(cxx_range_for) is true 
#else 
#warning __has_extension(cxx_range_for) is false 
#endif 

#if __has_feature(cxx_range_for) 
#warning __has_feature(cxx_range_for) is true 
#else 
#warning __has_feature(cxx_range_for) is false 
#endif 

int main() 
{ 
} 

Для меня, с -std = с ++ 03 его выходы:

test.cpp:4:2: warning: __has_extension(cxx_generalized_initializers) is false [-W#warnings] 
#warning __has_extension(cxx_generalized_initializers) is false 
^ 
test.cpp:10:2: warning: __has_feature(cxx_generalized_initializers) is false [-W#warnings] 
#warning __has_feature(cxx_generalized_initializers) is false 
^ 
test.cpp:14:2: warning: __has_extension(cxx_range_for) is true [-W#warnings] 
#warning __has_extension(cxx_range_for) is true 
^ 
test.cpp:22:2: warning: __has_feature(cxx_range_for) is false [-W#warnings] 
#warning __has_feature(cxx_range_for) is false 
^ 
4 warnings generated. 

Принимая во внимание, что с -std = C++ 11 выходные изменения:

test.cpp:2:2: warning: __has_extension(cxx_generalized_initializers) is true [-W#warnings] 
#warning __has_extension(cxx_generalized_initializers) is true 
^ 
test.cpp:8:2: warning: __has_feature(cxx_generalized_initializers) is true [-W#warnings] 
#warning __has_feature(cxx_generalized_initializers) is true 
^ 
test.cpp:14:2: warning: __has_extension(cxx_range_for) is true [-W#warnings] 
#warning __has_extension(cxx_range_for) is true 
^ 
test.cpp:20:2: warning: __has_feature(cxx_range_for) is true [-W#warnings] 
#warning __has_feature(cxx_range_for) is true 
^ 
4 warnings generated. 

Для Вашего случая использования, вы можете зашнуровать ваш код с __has_extension(cxx_generalized_initializers) и использовать новую функцию, когда правда, еще работают вокруг него, когда ложное. Затем ваш код будет автоматически адаптироваться при обновлении вашего clang или при изменении режима использования языка.

Что касается того, какая функция языка поддерживается, а какая нет, документация может помочь, но я считаю, что написать тест, такой как выше, является самым быстрым и точным способом оценить мою текущую версию clang.

+0

Ницца! Я написал небольшую программу, чтобы перечислить все функции. С точки зрения Clang 4.2 кажется, что * удаленные функции, встроенные пространства имен, аргументы шаблонов локального типа, переопределяющие ключевые слова управления, ссылочные квалифицированные функции, диапазон для ссылок * и * rvalue *. – nneonneo

+0

Что странно в том, что '__has_extension (cxx_auto_type)' является ложным, но (как вы можете видеть в моем примере) 'auto & i' компилируется просто отлично. – nneonneo

+0

@nneonneo: Кажется, что в Clang 3.3 (devel.версия), все тесты компилируются в 'true', за исключением 'cxx_inheriting_constructors'. И согласно [их таблице] (http://clang.llvm.org/cxx_status.html), кажется, что 'thread_local' также будет отсутствовать в следующей версии. Но он приближается. Я бы предположил, что они не делают значение '__has_extension' равно true, пока поддержка не станет окончательной и стабильной, поэтому' cxx_auto_type' может оценивать значение false, пока код работает. –