現実のコンパイラーにおいて、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.