LoginSignup
8
8

More than 3 years have passed since last update.

C++03 ユーザ向けの C++11 or later メモ

Last updated at Posted at 2019-08-12

背景

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

ヌルの値が, NULL0 ではなく 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 と解釈されるため, つらい思いをしました... :cry:

ポータビリティを上げるためにも, 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::mapO(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]]

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

!!!??? :scream:
https://www.reddit.com/r/cpp/comments/900dor/stdweb_view_proposal/

8
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8