最新C++事情
CORE 北海道カンパニー 社内勉強会
2018/10/13 松浦 明彦
(C++14,C++17,C++20)
— C++における型システム的な話題を中心に —
はじめに
C++とは?
C++98:ジェネリックプログラミング
C++11:関数型、型推論、メタプロ、std::chrono
C++14:ジェネリックラムダ
C++17:コンストラクタテンプレートパラメータ推論、他
C++20:コンセプト
さいごに
もくじ
2
はじめに
C++とは?
C++98:ジェネリックプログラミング
C++11:関数型、型推論、メタプロ、std::chrono
C++14:ジェネリックラムダ
C++17:コンストラクタテンプレートパラメータ推論、他
C++20:コンセプト
さいごに
3
何を話すか迷った
最初は「C++の最新機能ひとめぐり」を考えていたが、まあ、聞いている方は
つまんないだろうなあ、と。てか、膨大だし難解だし。
いろいろ考えた結果、C++の型システムまわりの話をしてみようかと思った。
最近、JavaVM言語/JavaScript界隈では型システムの話題がよく議論されてい
る。強い型付けを特徴とするC++は、型システムに対してどのような考え方を
持って生まれたのか、そして、それはどう進化し、どこへ向かっているのか
。C++の最新機能を紹介しつつ、そういった話題を提供することで、皆さんの
システム開発への関心がより深まってくれると良いな、って感じ。ま、それ
でも難解だと思うので、雰囲気だけでも感じ取っていただければ。なお、型
システムそのものについて、私は議論できるほどの知識も経験もない。その
へんはIKDさんに譲る。てか、今日はIKDさんにいろいろ突っ込まれそうだ(
笑)
4
私の履歴書
■ 日本語版レビュア
「C++の設計と進化」 Bjame Stroustrup
http://www.amazon.co.jp/dp/4797328541/
「ストラウストラップのプログラミング入門」Bjame Stroustrup
http://www.amazon.co.jp/dp/4798119598/
■ 自分の記事
「ユーザたちがつくり上げた言語 C++」(プログラミングの魔導少女)
https://sites.google.com/site/sapporocpp/linguamagi
公開スライド
http://www.slideshare.net/akihikomatuura/presentations
5
はじめに
C++とは?
C++98:ジェネリックプログラミング
C++11:関数型、型推論、メタプロ、std::chrono
C++14:ジェネリックラムダ
C++17:コンストラクタテンプレートパラメータ推論、他
C++20:コンセプト
さいごに
6
Bjame Stroustrup
7
ビアルネ・ストラウストラップ
C++の生みの親、C++の神、C++のハゲ
「C++は、C言語の効率性、柔軟性、システムズプログ
ラミングへの適性と、Simulaが持つプログラムの組織化
能力の、両方を合わせた言語として設計された。」
Simula:クラスとオブジェクトの概念を導入した最初期のオブジェクト指向言語
* 静的タイプシステムに対する暗黙の侵犯がない
* ユーザ定義タイプにも内蔵タイプと同格の良質なサポートを提供する
— 「C++の設計と進化」より
C++の設計思想
8
The Programming Languages Beacon
http://www.lextrait.com/vincent/implementations.html
世の中の主要なソフトウェアプロダクトは、その多くがC++で書かれている。
Windows/macOS/iOS、Office、DBMS、Web Browsers、IDE、コンパイラ、
JavaVM、.NET CLR、JavaScript Engine、更にはAmazonやFacebookのサーバ
ーサイドでも使われている。
この際だからはっきり言っておこう、
C++で開発されている
ソフトウェアプロダクト
「C++はプログラミング言語の王である」と
ごめん、言ってみたかっただけ(笑)
9
C++の歴史
1979 5月 C with Classesの開発を開始
1983 12月 C++と命名
1985 10月 Cfront Release 1.0(最初の商用リリース)
1990 5月 The Annotated C++ Reference Manual出版[ARM]
1998 9月 C++98(ANSIとISOよる最初の国際規格)
2003 10月 C++03(今でもC++というとこれだったりする)
2011 8月 C++11(めっさ進化した)
2014 12月 C++14
2017 12月 C++17(← 今ここ)
2020 C++20(予定)
10
はじめに
C++とは?
C++98:ジェネリックプロ
グラミング
C++11:関数型、型推論、メタプロ、std::chrono
C++14:ジェネリックラムダ
C++17:コンストラクタテンプレートパラメータ推論、他
C++20:コンセプト
さいごに
11
例:探す
探す条件例 : a == b
要素をたどる: ++a
要素を参照する: *a;
上記さえ満たせばあらゆる型に適用可能
template<typename Iterator, typename Tp>
Iterator find(Iterator first, Iterator last, const Tp& val)
{
while (first != last && !(*first == val)) ++first;
return first;
}
「探す」とは、ある条件に合致する要素を見つけること。それはデー
タ型には依存しない。
12
Generic Programing
// svから"X"を探す
vector<string> sv;
・・・
vector<string>::iterator i = find(sv.begin(), sv.end(), "X");
// arから5を探す
int ar[10];
・・・
int* pi = find( ar, ar+10, 5);
それはC++98のSTLで示された。オブジェクト指向に対するアンチテー
ゼとも言える。常にクラス(データ+操作)という選択が正しいわけで
はない。コンテナ、アルゴリズムをイテレータにて糊付けすることで、
タイプセーフに再利用を促進することができる。『使いたいアルゴリズ
ムを決めよ。様々な型、データ構造を操作対象にできるよう、「それら
をパラメータ化せよ」— Bjame Stroustrup』
13
はじめに
C++とは?
C++98:ジェネリックプログラミング
C++11:関数型、型推論、
メタプロ、std::chrono
C++14:ジェネリックラムダ
C++17:コンストラクタテンプレートパラメータ推論、他
C++20:コンセプト
さいごに
14
C++11関数型
(とラムダ式)
std::function<void(int)> func
= [](int x) { std::cout << "x is" << x; };
func(100); // x is 100
関数を第一級オブジェクトとして扱うという関数型自体は大昔か
らあるプログラミングパラダイムで、LISPやSchemeが起源。
2000年代半ばあたりからHaskell、F#、Scalaなど、関数型言語周
辺で活発な議論があった。C++は、C++11にて、関数型とラムダ
式を扱えるようになった。
→ 今ではどの言語も普通に備える機能ですね。
15
C++11:型推論(auto)
// std::function<void(int)> func = [](int x) { … };
auto func = [](int x) { std::cout << "x is" << x; };
func(100); // x is 100
auto b = v.begin(); // 以前は std::vector<int>::iterator b = ..
auto e = v.end();
auto f = std::find(s,e,100);
C#やJavaのvarとまあ同じ。C++はコンパイル時に型が決定さ
れる。
16
とある例:std::chrono
typedef int meter;
meter value = 10; // 10メートル
meter mValue = value; // おおっと、変換が必要だ
meter mValue = value * 1000; // 正しくはこう
//…「プログラミングの魔導書 Vol 1」より
よくあるバグ:
C++はこういった問題に対する解決策を持っている。
17
ratio、duration
typedef ratio<1, 1000000000> nano;
typedef ratio<1, 1000000> micro;
typedef ratio<1, 1000> milli;
typedef ratio<1, 100> centi;
typedef ratio<1, 10> deci;
typedef ratio< 10, 1> deca;
typedef ratio< 100, 1> hecto;
typedef ratio< 1000, 1> kilo;
typedef ratio< 1000000, 1> mega;
typedef ratio<1000000000, 1> giga;
ratio:コンパイル時に値が決定する有理数を表す型
18
ratio、duration
typedef duration<..., std::nano> nanoseconds;
typedef duration<..., std::micro> microseconds;
typedef duration<..., std::milli> milliseconds;
typedef duration<... > seconds;
typedef duration<..., std::ratio< 60> > minutes;
typedef duration<..., std::ratio<3600> > hours;
milliseconds ms(3); // 3 ミリ秒
microseconds us = ms; // 3 ミリ秒をマイクロ秒に変換
milliseconds ms2 = us; // 丸め誤差が発生するのでコンパイルエラー
duration:時間の単位
19
std::chrono
typedef int meter;
meter value = 10; // 10メートル
meter mValue = value; // おおっと、変換が必要だ
meter mValue = value * 1000; // 正しくはこう
//…「プログラミングの魔導書 Vol 1」より
時間や長さを単なる数値型で扱っていた時代を思い出そう。演算の
たびに単位が異なっていないか危惧し、外部I/Fのためにめんどくさ
い変換が必要になる。C++のdurationであれば単位は自動的に判断
され、誤差の発生する演算はコンパイルエラー、他の単位への変換
も自動的に行われる。
重要なのは、こういった機能を言語が直接提供しているわけでなく
、型システムと各種演算子オーバーロードを駆使することで、ライ
ブラリレベルで実現できている、ということ。
20
C++98以降:
テンプレート・メタプログラミング
型特性等を駆使して記述される「プログラムを生成
するプログラム」。壮大なテーマなので割愛する。
以前の勉強会でのプレゼン資料:
「C++ Template Meta Programming の紹介」
https://www.slideshare.net/akihikomatuura/c-template-meta-
programming
21
C++11その他:右辺値参照
C++11では「右辺値参照(rvalue reference)」が
入った。→ &&(アンパサ2つ使う)で装飾する型
。C++11以降では避けて通れない。
個人的にはC++11最大のトッピックだし、C++型シ
ステムに対する大きな変更だけど、「ここに記すに
は余白が狭すぎる」ので割愛する。
22
はじめに
C++とは?
C++98:ジェネリックプログラミング
C++11:関数型、型推論、メタプロ、std::chrono
C++14:ジェネリックラム
ダ
C++17:コンストラクタテンプレートパラメータ推論、他
C++20:コンセプト
さいごに
23
C++14:ジェネリックラムダ
(generic lambdas)
auto plus = [](auto a, auto b) { return a + b; };
C++11のラムダ式を拡張して、パラメータにテンプレートを
使用できるようにした機能
- パラメータリスト内のautoは、型をテンプレートパラメータに
するためのプレースホルダー
- template<T>書式は使用しない。
- まるでJavaScriptのようだ!
ジェネリックラムダ(
generic lambdas)
auto plus = [](auto a, auto b) { return a + b; };
auto result1 = plus(3, 2);
auto result2 = plus("Hello"s, "World"s);
std::cout << result1 << std::endl; // 5
std::cout << result2 << std::endl; // “HelloWold"
auto result3 = plus(1, "World"s); // ビルドエラー
// 整数型と文字列型の+演算はできない
念の為:動的に型が決定されるわけではない。コンパイル時
に決まりコードが生成される。
余談:Java11 :
ラムダ式内の型推論
BiFunction<Integer,Integer,Integer> f = (var x,var y) -> {
return x + y;
};
System.out.println(f.apply(10,10));
List<String> list = List.of("1","2","3");
list.stream().forEach((var s) -> {
System.out.println(s);
});
まあ、似てるっちゃ似てるが、型推論なのでラムダ式そのものを
ジェンリック化するわけではなく。てかJavaジェネリックはコンパイル時
の型保証であって、静的にその型のコードが..(略
はじめに
C++とは?
C++98:ジェネリックプログラミング
C++11:関数型、型推論、メタプロ、std::chrono
C++14:ジェネリックラムダ
C++17:コンストラクタテン
プレートパラメータ推論、他
C++20:コンセプト
さいごに
27
コンストラクタ・テンプ
レートパラメータ推論
template <class T>
struct Point {
T x, y;
// コンストラクタは、クラスのテンプレートパラメータT型のパラメータをとる
Point(T x_, T y_)
: x(x_), y(y_) {}
};
void ConstructorInference() {
// 以前はこうやって型を指定する必要があった
auto p1 = Point<int>(1,2);
// コンストラクタパラメータからPoint<int>であることを推論
auto p2 = Point(1,2); // もはやどこにも型の指定がない(JSか!
// javaではjava7くらいからだっけ?
// コンストラクタパラメータからPoint<double>であることを推論
auto p3 = Point(1.0,2.0);
C++17:std::any
std::any a;
a = 1; // 整数代入
std::cout << std::any_cast<int>(a) << std::endl; // 1
a = "abc"; // 文字列代入
std::cout << std::any_cast<const char*>(a) << std::endl; //abc
a = std::vector<int>(); // vectorも入れてみたりして
これがあの型に厳しいC++のコードだろうか! anyには、ほぼど
んな型でも入れることができる!! ・・・実は、普通にライブ
ラリレベル実装されており、boostにはずいぶん昔から存在して
いた。 → Type Erasureという古典的な技法
なお、Xcode 10 の場合ターゲットをmacOS 10.14(Mojave)にする必要あり。(
bad_variant_access exception てのが10.14から)
はじめに
C++とは?
C++98:ジェネリックプログラミング
C++11:関数型、型推論、メタプロ、std::chrono
C++14:ジェネリックラムダ
C++17:コンストラクタテンプレートパラメータ推論、他
C++20:コンセプト
さいごに
30
コンセプト(Concept)とは
コンセプトとは「型を記述するメタな型」
C++11の主要な機能の1つになるはずだったがドロップされ
た。→ コンセプトマップの自動生成まわりで激しい議論があったとか。Bjarne Stroustrupも
ドロップに賛成したらしい。
で、長い議論の末、C++20でついに採用される予定
以下、「予定」なので実際にどうなるかはまだわからない。
また、手元のコンパイラはコンセプト未サポートなため実際の動作検証は出来ていない。あ
と、不勉強で不正確な可能性あり、ごめん。
C#のジェネリックにおける制約条件(where)とちょっと似ているかも。別物だけど。
あ、
31
コンセプト導入の目的
(よく言われるやつ)
http://d.hatena.ne.jp/spinor/20111215/1323951052
C++03 テンプレートの課題を解決したい:
テンプレート定義時に、仮引数が備えるべきインタフェー
スが意識されないこと
テンプレート実引数にヘンテコな型を渡しても、テンプレ
ートが実体化されるまで、コンパイラのエラー検知が遅れ
ること
冗長なエラーメッセージ
32
真の目的:Bjarne は語る
「本の虫」より(Bjarne Stroustrup、Conceptと未来を語る)
https://cpplover.blogspot.com/2009/08/bjarne-stroustrupconcept_14.html
Conceptの規格を設計することは難しい。というのも、C++の型システムそのものだ
からだな。
Conceptの規格を正しく設計するというのは、C++規格の不明確な部分を整理すると
いうことだな。
もっと重要な利点とは、プログラミングスタイルとコード品質なのだ。
Conceptはあるひとつの目的の為に導入されたのだ。ジェネリックプログラミングと
いうテンプレートの高度な使い方を、直接言語側でサポートするためだ。
現状では、コメントだとか、仕様書だとか、ドキュメントの中で記述しているような
ことを、直接表現できるようにする為なのだ。よくデザインされたテンプレートコー
ドというのは、引数の型にどのような操作をするのかを、きちんと考えて書かれてい
るのだ。良いコードというのは、そういう必要条件という考えが、ドキュメント化さ
れているものだ。
33
簡単な例1
// Drawableコンセプトは型Tがdrawを持っていることを要求
template<typename T>
concept bool Drawable = requires(T t) { t.draw(); } ;
class Shape { // ...
void draw();
};
class Cowboy { // ...
void draw();
};
// 型パラメータであるDはDrawableコンセプトに適合している必要がある。
template<Drawable D>
void draw_all(vector<D*>& v) { // ye olde draw all shapes example
for (auto x : v) x->draw(); // → 原文はv->draw()だけど間違ってる
}
P0557R0 Concepts: The Future of Generic Programming より
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0557r0.pdf
「型を記述するメタな型」
従来は typename でしかなかった
例2
template<typename T> // 加算可能のconcept
concept bool Addable = requires(T a, T b) {
{ a+b } -> T; // a+bが可能で評価結果はTである
};
template<typename T> // 数値型のconcept
concept bool Number = requires(T a, T b) {
{ a+b } -> T; // a+bが可能で評価結果はTである
{ a-b } -> T; // a-bが可能で評価結果はTである
{ a+=b } -> T&; // a+=bが可能で評価結果はT&である
・・・
};
// ソート可能を定義するconcept
template<typename T> concept bool Sortable =
Sequence<T> && // シーケンスで
Random_access_iterator<Iterator_of<T>> && // ランダムアクセス可能で
Less_than_comparable<Value_type<T>>; // "<" で比較可能
はじめに
C++とは?
C++98:ジェネリックプログラミング
C++11:関数型、型推論、メタプロ、std::chrono
C++14:ジェネリックラムダ
C++17:コンストラクタテンプレートパラメータ推論、他
C++20:コンセプト
さいごに
36
さいごに(1/2)
C++の型システムに対する拘りを感じてもらえたかと思いま
す。
プログラミング言語のポリシ・設計・進化の理解はとても重
要です。例えば、C++コンセプトは今のところC++独自のも
のと思うが、「プログラミングスタイルとコード品質」を言
語そのものがサポートする、という考えは、他の言語にも普
及するのでは無いか、と思える。→ インターフェースと実装の
分離は永遠のテーマであり、インターフェースはClassやInterfaceで
ある必要はなく、もっとメタかつデザイン寄りであって良いハズ
37
さいごに(2/2)
「言語の勉強ばっかりしても意味ない」→ もちろん正しいとおもう
「言語の勉強をしても大して意味はない」 → ではない
プログラミング言語は常に進化しており、その進化は、システム開発における
設計、アーキテクチャ、あるいはハードウェアの進化に寄り添っている。もし
くは、それらをリードする場合すらある。つまり、本気でシステム開発にコミ
ットし学習を続けている技術者は、自然といくつかの言語に詳しくなる。ある
いは、言語の学習を通してシステム開発に求められる概念を理解することもあ
る。
結局、言語の勉強をするなら、表面的なシンタックスだけの理解では不足であり、
その裏側にある意味論(セマンティクス)を理解しなければ意味がない。逆に、セ
マンティクスの理解なくして真の理解はない。というわで、皆さん安心して勉強し
てください(笑)。とはいえ、「We need good programmers far more than we
need yet-another language lawyer.」(Bjarne Stroustrup):「欲しいのは良いプログラ
マであって、言語ヲタクではない」
38
ご清聴ありがとうございました
。
今回も勉強になりました。僕が。
39

最新C++事情 C++14-C++20 (2018年10月)