背景
C++ の知識が 03 あたりで止まっていて, 昨今の C++ の進化に追いつくために精進が必要である.
スパコンからモバイル/組み込み/JIT 用などの特殊用途と, 幅広い領域を対象として C++ コード開発を行なっているため, なかなか最新の C++ 標準や最新コンパイラを使うということが難しく, C++03 に甘んじている.
(C++03 だと 2019 年 8 月時点で, ほぼどんな C++ コンパイラや環境でも対応されているため)
とはいえ, 某スパコン向けコンパイラもついに C++11 or later 完全対応になるようなので(まあ clang/libc++ のおかげではあるのですが), 最低限 C++11 には移行したい.
STL 成分が多め.
C++11
C++03
メジャーなコンパイラでの対応状況
https://gcc.gnu.org/projects/cxx-status.html
https://clang.llvm.org/cxx_status.html
https://docs.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=vs-2019
コンパイラ自体での対応と, STL での対応と, コンパイラ/STL 両方での対応との兼ね合いがあり, ややこしいが, 基本的には以下でしょうか
- gcc 4.9 or later
- 後述するが, RHEL7(Centos7)標準の gcc 4.8 は C++11 対応が完全ではないことに注意.
- clang 3.3 or later(clang 3.9 or later が安全?)
- Visual Studio 2015.2 or later(2017 or later が安全?)
nullptr
ヌルの値が, NULL
や 0
ではなく nullptr
になりました.
たとえば, clang で -Weverthing
とワーニング MAX にすると, NULL
, 0
にしているところはワーニングを表示してくれます.
cstdint
符号やビット長の決まったプリミティブ型が標準で使えるようになりました.
C++03 では, たとえば uint64_t など 64 ビット整数を指定する確実な指定方法がありませんでした.
(C++03 では typedef unsigned long long uint64_t
などとしていましたが, long long が必ずしも 64bit とは限らない)
特に, arm 環境では char
は(コンパイラによるが, たとえば gcc/clang では)デフォルトでは unsigned char
と解釈されるため, つらい思いをしました...
ポータビリティを上げるためにも, cstdint
を使い int8_t
, uint8_t
などを使うのが理想です.
(正確には cstdint
は C11 の定義で, C++11 の定義ではないかも....?)
auto
型推論してくれる. 便利だけと多用すると型がよくわからなくなるかも?
コードスニペットがあれば, C++ insight で実際の型を表示(deduce)できます.
auto
は, 昔はローカル変数を指定するものとして使われていました.
range based for
for (auto &item : dict) {
}
のようにかける. std::map
をイテレートするときに便利.
Python enumerate
のようにインデックスも欲しいときは, 直接には実現するものはないので, 追加でいろいろと実装が必要となる.
C++17 だと structural binding が使えて, より python 風に書ける.
decltype
式から型を取得できる.
attributes
C#
の attribute, Python のデコレータみたいなものかしら.
Initializer list(list initialization)
うまく使うとコードがスッキリかけます.
クラスメンバ変数の初期化
class A
{
int a = 42;
};
のようにクラスのメンバ変数でデフォルト値を設定できるようになりました.
コンストラクタなどでの設定忘れのミスを低減してくれますね.
(ところでメンバ変数がコンストラクタで初期化していないときに warning を出してくれるコンパイラオプションは無いかしら?)
override
仮想関数をオーバーライドしているのを確実にするのに使える.
fma
Fused-Multipy Add が使えるようになり, 精度の必要な数値計算に役立ちます.
いままではコンパイラの独自拡張や, SSE などの instrinsic 命令で対応しなければなりませんでしたので, ポータビリティが上がりました.
std::begin, std::end
.begin()よりもstd::begin()を使うと配列とコンテナを同様に扱える
https://qiita.com/rennone/items/f2d1612b6273d6c034ae
ありがとうございます.
std::random
MersenneTwister とかでの擬似乱数生成がお手軽にできるようになりました.
一様分布やガウス分布なども選べます.
double の一様乱数生成は難しいですが,
うまく実装されているかしらん?(STL のコードを見る必要がありますね)
モンテカルロレンダリングなどで昨今の流行りである pcg32 アルゴリズムは入っていません http://www.pcg-random.org/
std::regex
regex が使える. gcc4.8(RHEL7/CentOS7)では regex 実装は完全ではないので, コンパイルはできるかもだが実行するとクラッシュするので gcc4.8 で std::regex
を使わないようにしましょう.
std::unordered_map
ハッシュキーによる map. std::map
より効率がよいのが期待される.
std::map
は O(logN)
std::unordered_map
は, 平均的に O(1)
, ワーストケースで O(N)
オブジェクトに対して, ハッシュが求まることが必要.
std::thread, std::atomic, std::mutex
スレッドやアトミック操作が C++ STL で標準化されていてよい.
pthread や win32 スレッド API を叩く必要がなくなってよい.
ただし STL 実装(コンパイラ実装)によっては, 一部環境(某スパコンコンパイラとか, あまりメジャーではない環境)によっては対応していないものがあるかも...?
std::thread::hardware_concurrency
で CPU のスレッド数が取得できるが, 0 が帰ってくる可能性もあるようです(メジャーな環境では 0 に遭遇したことはありませんが).
uint32_t num_threads = std::max(1, std::min(128, std::thread::hardware_concurrency())
のようにして, 上限下限を設定してクランプするとよいでしょう.
std::chrono
計測がやりやすくなる.
std::tuple
std::pair は 2 個までだったが, 3 個以上の要素に対応
std::array
固定長の配列. ベクトル変数などで使うとよい.
move semantics, 右辺値(rvalue)参照
いろいろと解説記事が他にあります.
lambda
ラムダ式が使える. 上記 std::thread
と組み合わせると, イベントベース処理がスッキリかけたりする.
std::find_if
std::find_if と lambda 式を組み合わせると, 一致する要素を探すというロジックが記述しやすくなります.
Variadic template
テンプレートで可変長の引数に対応できる.
fmtlib
のような型安全 (s)printf の実装に使えたりする.
func
__func__
マクロが標準で定義され, 関数名が取得できるようになった.
引数などにも指定できるようですが, ログ関数とかで行番号などを表示したいときは, いままで通りマクロで関数を定義しないとうまく展開されません.
C++11 で追加された STL
C++14
C++11 の強化版. constexpr がより強化(制限が緩和)
2019 年 8 月時点では, メジャーなコンパイラや環境であれば C++14 を使うのが推奨そうです.
https://ja.wikipedia.org/wiki/C%2B%2B14
C++17
ナウでヤングな 2019 年 8 月時点では最新の標準.
gcc, clang, MSVC の 2019 年 8 月時点での最新バージョンは一通り C++17 対応している... はず?
C++17 までくるともはや C++03 なコードとは全然ちがいますね.
[[nodiscard]]
Are you a C++ programmer with a vector math library (perhaps you're a game developer)? With a Vec3::Normalize function that returns a Vec3 rather than operating in-place? Go and mark that function as [[nodiscard]] right now. You're welcome.
— Hatsune Mimikyu 🌸 (@lunasorcery) August 16, 2019
vector3 などので有益っぽい.
Parallel STL
@yumetodo さまからご指摘いただきました.
sort()
とか, algorithm のいくつかで並列処理ができるようになっています.
Intel TBB とかに依存しないポータブルなコードが書けます.
std::filesystem
ファイルの扱いが楽になりますね.
(ただし Android NDK では, コンパイラは C++17 対応のようであるが, std::filesystem についてはまだサポートされていない https://github.com/android-ndk/ndk/issues/609 )
std::variant
型セーフな union.
テンプレートでインターフェイスベースの書き方ができてよい.
std::visit と組み合わせることで, AST(Abstract Syntax Tree)処理も書きやすくなる.
boost::variant
と異なり, 再帰には対応していないので自前で追加実装が必要.
再帰ができると, JSON の表現ができたりする. Mapbox 先生の variant 実装参考.
https://github.com/mapbox/variant
std::any
std::variant は静的な型でしたが, std::any
は動的な型をサポート. より Python のようなことができるようになる... はず?
STL その他
std::optional
Haskell Maybe のようなものが実現できる
std::string_view
, std::span
特定の領域を参照(リードオンリー)だけすることができる.
省メモリ化とか効率化に役立つかも.
nonstd-lite project
Martin 先生による, C++11(一部は C++98, C++03 でも動く)での STL のバックポート的実装.
ありがたく使わさせていただきましょう.
STL の置き換え(backport)
C++98/++03/C++11 でも C++14, 17, 20 の機能を使いたい. たとえば filesystem とか.
nonstd-lite
any, byte, expected, optional, span, string_view, variant あたりがあります
variant については, mapbox variant が再帰もサポートしていますので mapbox variant を推奨です.
filesystem
An implementation of C++17 std::filesystem for C++11 /C++14/C++17 on Windows, macOS and Linux
https://github.com/gulrak/filesystem
ありがとうございます.
その他
std::audio が提案されています
JUCE の人たちが提案していますね.
std::web_view
!!!???
https://www.reddit.com/r/cpp/comments/900dor/stdweb_view_proposal/