2014-12-16

C++14に入る機能テストマクロの一覧

現実のコンパイラーにおいて、C++11やC++14、そして今制定されようとしている各種TSやC++1zなどの機能は、個々に実装される。その場合、あるコンパイラーのあるバージョンは、rvalueリファレンスを実装している、その次のバージョンはconstexprを実装したという、中途半端に機能を実装した状態になる。

その結果、現実には、往々にして以下のようなコードが書かれることになる。

#ifndef __USE_RVALUE_REFERENCES
  #if (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 3) || \
      _MSC_VER >= 1600
    #if __EDG_VERSION__ > 0
      #define __USE_RVALUE_REFERENCES (__EDG_VERSION__ >= 410)
    #else
      #define __USE_RVALUE_REFERENCES 1
    #endif
  #elif __clang__
    #define __USE_RVALUE_REFERENCES __has_feature(cxx_rvalue_references)
  #else
    #define __USE_RVALUE_REFERENCES 0
  #endif
#endif

標準規格としては、一部機能だけ実装することを推奨するのではないが、現実がこうである以上、ある機能が実装されているかどうかを調べる標準のプリプロセッサーマクロが存在するべきである。

そこで提案されているのが、Feature-testing recommendations for C++だ。

この提案では、C++の主要機能が実装されている場合、特定の名前のプリプロセッサーマクロが事前に定義されることとなる。例えば、rvalueリファレンスの場合、__cpp_rvalue_referencesという名前のプリプロセッサーマクロが定義される。

マクロの名前は、名前の衝突を避けるため、プレフィクスが付けられる。コア言語機能ならば__cpp_、ライブラリー機能ならば__cpp_lib_である。機能名は、その機能の論文のタイトルから採用される。

マクロの値は、その機能がドラフトに採用された年と月を表現している。これにより、標準規格策定中にドラフトが更新された場合、値も更新される。たとえば、C++11の機能である__cpp_rvalue_referencesの場合、2006年の10月にドラフト入りしたので、その値は200610となる。

特定のヘッダーファイルがあるかどうかを調べるプリプロセッサーの機能、__has_includeが追加される。これは、#ifや#elifの中で使うことができる。

#ifdef __has_include
#  if __has_include(<optional>)
#    include <optional>
#    define have_optional 1
#  elif __has_include(<experimental/optional>)
#    include <experimental/optional>
#    define have_optional 1
#    define experimental_optional
#  else
#    define have_optional 0
#  endif
#endif

機能テスト推奨に対応している実装で、#ifdefで__has_includeを記述すると、定義済みだと評価される。#ifや#elifで__has_include(ヘッダー)と記述すると、そのヘッダーが存在する場合はtrueとなる。

同様に、特定のattributeがあるかどうかを調べるプリプロセッサーの機能、__has_cpp_attributeが追加される。

#ifdef __has_cpp_attribute
#  if __has_cpp_attribute(deprecated)
#    define ATTR_DEPRECATED(msg) [[deprecated(msg)]]
#  else
#    define ATTR_DEPRECATED(msg)
#  endif
#endif

具体的なマクロ名

実際に論文を読めばいいと思うのだが、とりあえずここにも書いておく。ほとんどの機能は、このブログやC++11の参考書で解説したはずだが、まだ知らない読者はいるのだろうか。なにか新たに解説して欲しい機能があればコメントで言えば解説するつもりだ。

C++98機能

機能 セクション番号 マクロ名 ヘッダー
実行時型情報 5.2 __cpp_rtti 199711 predefined
例外 15 __cpp_exceptions 199711 predefined

C++11機能

文書番号 文書名 セクション番号 マクロ名 ヘッダー
N2249 ユニコード文字型 2.13 __cpp_unicode_characters 200704 predefined
N2442 生文字列リテラルとUnicode文字列リテラル 2.13 __cpp_raw_strings 200710 predefined
__cpp_unicode_literals 200710 predefined
N2765 User-defined Literals 2.13, 13.5 __cpp_user_defined_literals 200809 predefined
N2927 lambda式 5.1 __cpp_lambdas 200907 predefined
N2235 constexpr 5.19, 7.1 __cpp_constexpr 200704 predefined
N2930 Range-Based for 6.5 __cpp_range_based_for 200907 predefined
N1720 static_assert 7 __cpp_static_assert 200410 predefined
N2343 Decltype 7.1 __cpp_decltype 200707 predefined
N2761 属性(attribute) 7.6 __cpp_attributes 200809 predefined
__has_cpp_attribute(noreturn) 200809 predefined
__has_cpp_attribute(carries_dependency) 200809 predefined
N2118 rvalueリファレンス 8.3 __cpp_rvalue_references 200610 predefined
N2242 可変長テンプレート(Variadic Templates) 8.3, 14 __cpp_variadic_templates 200704 predefined
N2672 初期化リスト(Initializer List) 8.5 __cpp_initializer_lists 200806 predefined
N1986 コンストラクターのデリゲート 12.6 __cpp_delegating_constructors 200604 predefined
N2756 非staticデータメンバーの初期化子 12.6 __cpp_nsdmi 200809 predefined
N2540 継承コンストラクター 12.9 __cpp_inheriting_constructors 200802 predefined
N2439 リファレンス修飾子(*thisへのムーブセマンティクス) 13.3 __cpp_ref_qualifiers 200710 predefined
N2258 テンプレートエイリアス 14.5 __cpp_alias_templates 200704 predefined

C++14機能

まだこのブログで詳細に解説していない機能もあるはずだ。

文書番号 文書名 セクション番号 マクロ名 ヘッダー
N3472 2進数リテラル 2.14 __cpp_binary_literals 201304 predefined
N3781 シングルクオートによる数値区切り 2.14 __cpp_digit_separators 201309 predefined
N3648 汎用lambdaキャプチャー 5.1 __cpp_init_captures 201304 predefined
N3649 ジェネリックlambda式 5.1 __cpp_generic_lambdas 201304 predefined
N3778 サイズ付き解放関数 5.3, 18.6 __cpp_sized_deallocation 201309 predefined
N3652 constexpr関数の制限緩和 5.19, 7.1 __cpp_constexpr 201304 predefined
N3638 関数の戻り値の型推定 7.1 __cpp_decltype_auto 201304 predefined
__cpp_return_type_deduction 201304 predefined
N3760 [[deprecated]]属性 7.6 __has_cpp_attribute(deprecated) 201309 predefined
N3653 アグリゲート初期化とメンバー初期化子の同時利用 8.5 __cpp_aggregate_nsdmi 201304 predefined
N3651 変数テンプレート 14, 14.7 __cpp_variable_templates 201304 predefined
N3658 コンパイル時整数シークエンス(index_sequence) 20 __cpp_lib_integer_sequence 201304 <utility>
N3668 exchange()関数 20 __cpp_lib_exchange_function 201304 <utility>
N3670 tupleで型を指定できるget 20.2-20.4 __cpp_lib_tuples_by_type 201304 <utility>
N3887 テンプレートエイリアスを使ったtuple_element_t 20.3-20.4 __cpp_lib_tuple_element_t 201402 <utility>
N3656 make_unique 20.7 __cpp_lib_make_unique 201304 <memory>
N3421 greater<>のテンプレート実引数の省略 20.8 __cpp_lib_transparent_operators 201210 <functional>
N3462 std::result_ofをSFINAEフレンドリーにする変更 20.9 __cpp_lib_result_of_sfinae 201210 <functional>
N3545 integral_constantにconstexprなoperator ()を追加する変更 20.9 __cpp_lib_integral_constant_callable 201304 <type_traits>
N3655 エイリアステンプレートでメタ関数をラップして::typeを_tにする変更 20.9 __cpp_lib_transformation_trait_aliases 201304 <type_traits>
LWG 2112 is_finalの追加 20.10 __cpp_lib_is_final 201402 <type_traits>
LWG 2247 std::nullptr_t可動化を調べるis_null_pointer 20.10 __cpp_lib_is_null_pointer 201309 <type_traits>
N3642 chronoとstringに対するユーザー定義リテラルの追加 20.11 __cpp_lib_chrono_udls 201304 <chrono>
21.7 __cpp_lib_string_udls 201304 <string>
N3657 連想コンテナでkey_typeに変換可能な型から検索する機能 23.4 __cpp_lib_generic_associative_lookup 201304 <map>
<set>
N3644 Null Forward Iterators 24.2 __cpp_lib_null_iterators 201304 <iterator>
LWG 2285 make_reverse_iterator 24.5 __cpp_lib_make_reverse_iterator 201402 <iterator>
N3671 equal, mismatch, is_permutationで二つのrangeをとるオーバーロード 25.2 __cpp_lib_robust_nonmodifying_seq_ops 201304 <algorithm>
N3779 std::complexのユーザー定義リテラル 26.4 __cpp_lib_complex_udls 201309 <complex>
N3654 quotedライブラリ 27.7 __cpp_lib_quoted_string_io 201304 <iomanip>
N3659 shared_mutex 30.4 __cpp_lib_shared_mutex
__has_include(<shared_mutex>)
1 predefined
N3891 shared_mutexをshared_timed_mutexに改名 30.4 __cpp_lib_shared_timed_mutex 201402 <shared_mutex>

疲れた。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

No comments:

Post a Comment

You can use some HTML elements, such as <b>, <i>, <a>, also, some characters need to be entity referenced such as <, > and & Your comment may need to be confirmed by blog author. Your comment will be published under GFDL 1.3 or later license with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.