スレッドの終了を考える

別のスレッドを中断して終了したい場合どのように設計したらよいでしょうか?
昔悩んだことをメモしてみました。

メインスレッドから重い処理をさせるワークスレッドを止めたい場合を考えてみます。

//work thread
while(true) {
 // do work
}

//Main thread
cancel();

まずwork threadのループ部分のコードには手を入れずにMain threadから終了できるかどうかですが、一応そのような手段はありますがこれらはあまりにも問題が多く実質利用できないと考えるべきです。
Win32API なら TerminateThread();
pthread なら pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS) を指定したスレッドに対して pthread_cancel();
これらはいつでも目的のスレッドを終了できますが、いつでも終了できるということはリソースの確保中だろうが解放中だろうが問答無用で終了してしまうということです。当然おかしなことになりますよね。つまりnewやmalloc、mutexなどの同期オブジェクト、スレッド間で共有するデータ構造など大抵のリソースが使用できないということになります。リソースが確保前、確保中、確保後、解放中、解放後かどうか判別することはできません。その他にも環境依存の制約があります。

TerminateThread();//(WIN32API) too bad
pthread_cancel(); //(pthread) too bad with PTHREAD_CANCEL_ASYNCHRONOUS

ではC++例外を外部からwork thread内で何とかして(アセンブラなどで)投げられないでしょうか?
残念ながらこれも実質無理です。例外モドキを投げられたとしても上記と同じリソースの問題に直面することになります。
つまり、work threadに手を入れずに外部から「いつでも」終了できるようにすることは実質できないのです。

ではどうしたらよいのでしょうか?
正解はwork threadに手を入れることになります。

struct thread_aborted{}; //適当にこしらえた例外クラス
std::atomic<bool> exit_flag(false);

//work thread
try {
 while(true) {
  // do work
  check_exit();
 }
} catch (thread_aborted& e) {
}

void check_exit() {
 if (exit_flag)
   throw thread_aborted{}; //スレッドの終了は例外を投げるのが簡単でよい。
}

//Main thread
void cancel() {
 exit_flag = true;
}
cancel();

このように定期的に check_exit() を呼び出して終了フラッグを調べるようにします。スレッドが自ら終了する場合は何の問題もありません(ただし低レベルなスレッド終了関数を使用するのは避けましょう。理由は後述)。自スレッドを終了させる場合は return してもよいですが関数がネストしていると面倒ですので例外を投げてからcatchしてreturnするのが簡単です。例外はcatchしておかないとstd::terminate()が呼び出されてプログラム全体が終了してしまうことだけには気を付けてください。check_exit() を呼び出す頻度はレスポンスと負荷のトレードオフで決定しなければなりません。
この check_exit() を interruption points や cancellation points と呼びます。

これらと同様もしくはそれ以上に優れた仕組みが boost.thread に用意されています。
check_exit() が boost::this_thread::interruption_point() に相当し、cancel() は boost::thread::interrupt() に相当します。boost.thread は interruption points で boost::thread_interrupted 例外が throw されます。
interruption points は予め特定の待機関数でも設定されていますので

    boost::thread::join()
    boost::thread::timed_join()
    boost::thread::try_join_for()
    boost::thread::try_join_until()
    boost::condition_variable::wait()
    boost::condition_variable::timed_wait()
    boost::condition_variable::wait_for()
    boost::condition_variable::wait_until()
    boost::condition_variable_any::wait()
    boost::condition_variable_any::timed_wait()
    boost::condition_variable_any::wait_for()
    boost::condition_variable_any::wait_until()
    boost::thread::sleep()
    boost::this_thread::sleep_for()
    boost::this_thread::sleep_until()
    boost::this_thread::interruption_point()
    //boost threadのドキュメントより

これらの関数を呼び出しているところでも終了することができます。

void work() {
 while(true) {
  //do work
  boost::this_thread::sleep_for(seconds(60));
 }
}

boost::thread thr(work);
//...
thr.interrupt();//sleep_forのところで待機中ならすぐに終了できる。
// 詳しく書くとworkスレッドが sleep_for を実行中に thread_interrupted例外が投げられ
// その結果としてworkスレッドが終了する。
// thread_interrupted例外はboost.threadライブラリが良きに計らってくれるため
// 特にユーザーがcatchする必要はない。

これらの待機関数に interruption points が設定されていることのメリットはただ単に自分で interrruption_point() を書く手間が省けるというだけではありません。自作 check_exit() を使用した場合を考えてみましょう。

void work() try {
 while(true) {
  //do work
  sleep_for_60seconds();
  check_exit();
 }
} catch (...) {
}

cancel();

スレッドが do work 部分を実行中に外部から cancel() を呼び出してもスレッドは do work を終えた後 sleep_for_60seconds() に突入し60秒間も何も反応しません。その後ようやく check_exit() に突入して晴れてユーザーを1分も待たせたのちに終了することになるのです。つまり自作の check_exit() よりも待機関数と融合した boost.thread の interruption points の方がより高いレスポンスを期待できます。
しかしながら時には対応外の他のライブラリの待機関数を組み合わせたい場合が出てきます。こんな時には待機関数に短いタイムアウトを設定して

void sleep_for_60seconds() {
 for (int i=0; i<60; ++i) {
  other_librarys_sleep_for(seconds(1));
  check_exit(); //interruption points
 }
}
//本題から逸れるが細かく分割するほど待機する時間に誤差が蓄積しやすいので
//それを気にする場合はもう少し工夫が必要。

このように細切れに interruption points を挟みます。この例に限らず連携の取れない通知オブジェクトをシングルスレッドで待機するにはポーリングが必要になります。別のスレッドを使用すれば互換性のない待機関数同士を組み合わせるということができる場合もあります。別のスレッドで通知を待機しておいてから元のスレッドで待機可能な通知を投げるという感じです。

連携の取れない待機関数を使う boost::thread をポーリング無しで中断したい場合は boost::thread::interrupt() を使用せずに直接待機可能な通知があればそれを発行して終了処理する方が簡単です。例えばネットワークプログラムを boost.asio を使って書いているとしたら、待機関数の boost::asio::io_service の run() に対して post() など。因みに std::thread では interrupt() はサポートされていませんが、普通は待機関数に合わせた通知方法を選択する場合が多いと思いますのでそこまで不便はしないでしょう。標準に condition_variable もありますし、C++20からはstd::jthreadとstd::stop_tokenが導入される予定です。

boost::asio::io_service io;
//here: register async handler
std::thread thr([&]{ 
 try {
  io.run();
 } catch(std::runtime_error& e) {}
});
//以下のラムダ式が作成したスレッド内のio.run()で実行される
io.post([]{ throw std::runtime_error("aborted"); });
thr.join();


何れにしろ待機関数と通知方法を互換性のある一つの種類に統一することがポーリングを回避し、高レスポンスを実現する近道です。

スレッドの終了関数について
ExitThread, _endthread, _endthreadex の問題点

これらの関数はC++デストラクタを呼び出しません。使用するのはやめましょう。

pthread_exit, pthread_cancel の問題点

pthread_exit を呼び出してもC++デストラクタが呼び出される保証はありません。しかし主流な実装では呼び出されるようです。

また pthread_cancel() は他スレッドから pthread_setcanceltype( PTHREAD_CANCEL_DEFERRED ) が設定されたスレッド(デフォルトで設定されている)に対して特定の関数の cancellation points でスレッドを終了できますが、これも pthread_exit() と同じでC++デストラクタが呼び出される保証はありません。また仮にC++デストラクタが呼び出されるとしてもどの関数に cancellation points が設定されているのかすべて把握し、それらの関数を呼び出しているすべての個所で中断されることを想定したコード(リソースを使用しない or RAIIを使用する or リソースを回収するクリーンナップハンドラを登録する。かつデータの整合性を保つ必要がある。)が書かれていることを保証しなければなりません。これは現実的にはかなり難しいでしょう。つまり例えば fopenにcancellation pointが設定されていてその関数内では適切にハンドリングされている処理系であったとしても、普通のCやC++のコードはfopen関数が途中で(戻り値も返さずに)中断される可能性があるとは思ってもいないわけです。そこでこれを回避するために pthread_setcancelstate() を駆使して必要なところ(目の届く範囲)でのみキャンセルが有効になるようにしますがそれでも細心の注意と労力が必要になります。
Special thanks @yohhoyさん


結局自スレッドを終了する場合においても低レベルなスレッド関数の使用は避けC++の流儀に則って関数を return するか throw するのがよいでしょう。

スレッドライブラリについて

そもそもスレッドはライブラリとして実装できない(コンパイラの最適化を抑止できない)という話が存在するためpthreadなどを直接使用せずに言語仕様の一部であるstd.async、std.thread、std.mutexなどを使用するのが理想的でしょう。移植性の面からも望ましいです。

おまけ boost.thread + boost.asio のポーリング版

io_service には poll() や poll_one()、run_one() といったメンバ関数が存在しますがこれら自体は中断させる機構を作る用途には向いていません。poll_one() を使用してIOの性能や応答性を高めようとすれば負荷が気になりますし、poll() はそれに加えて処理するハンドラの最大値もしくはタイムアウトを設定できません。run_one() もタイムアウトを設定できません。結局タイマーを使用して io_service から定期的に interruption point を含むハンドラを呼び出すのがポーリングをする場合にはよさそうです。

#include <chrono>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/thread.hpp>

int main(){
  boost::asio::io_service io;
  //here: register async handler

  boost::thread thr([&]{
    boost::asio::steady_timer t(io); 
    std::function<void(boost::system::error_code const&)> handler;
    handler = [&](boost::system::error_code  const&){
      boost::this_thread::interruption_point();
      t.expires_from_now(std::chrono::seconds(1));
      t.async_wait(handler);
    };
    handler({});
    io.run();
  });
  thr.interrupt();
  thr.join();
  return 0;
}

C++の記号一覧 (List of C++ symbols)


検索のしづらいC++の記号の意味をまとめてみました。C++11、C++14をはじめとして網羅的に集めたつもりです。
C言語についての記述もありますが、共通した記号であってもC++とCでは文法や動作の子細が異なる場合がありそのまま適用できないことがあります。また掲載してある記法は説明のために載せているのであってすべてが推奨できるわけではないことにご注意ください。用語や分類、解説はかなりいい加減です。


[素数]配列型(要素数は定数でなければならない。要素数を省略した型は不完全型)。

typedef int array[5]; //配列型int[5]にarrayという名前を付ける。
void f(int ptr[]); //関数の宣言に用いてvoid f(int* ptr);と同じ
void f(int ptr[5]); //この場合要素数の記述は無意味で上記と同じ。

//動的配列の確保(まずはstd::vectorを検討したほうがよい)
auto r = boost::make_shared<int[]>(5); //値初期化される

new 型[素数]配列版のnew演算子。動的配列を確保する(要素数が定数である必要はない。また0も指定できる)。注意点は下記の delete [] を参照。

//動的配列の確保(まずはstd::vectorを検討したほうがよい)
//値初期化するには後ろに()や初期化リストの{}を付ける
std::unique_ptr<int[]> p( new int[5]() );
boost::shared_ptr<int[]> q( new int[5]{0,1,2,3,4} );
//スマートポインタのテンプレートパラメータにはint[]のように
//同じく配列型を指定する

型 名前[素数]固定長配列の宣言(要素数は定数でなければならない。推測可能な場合に省略可)。 std::arrayクラスの方がより扱いやすい。C99ではローカル変数の配列長を動的に指定できる。またgcc拡張、VC拡張、C99では構造体の最後に長さ0の配列を宣言でき可変長の構造体を宣言できる。

int name[4][3]; //3x4の二次元配列 (値初期化する場合は{}か={}を使う)
//最終次元の2は省略して初期化リストから推測させる
int name[][3] = {{},{}}; //3x2の二次元配列
char moji[] = "yes"; //char配列が yes\0 で初期化され要素数は4となる
//配列型は暗黙のうちにその先頭要素へのポインタへ変換されるため注意
char* p = moji; 
assert(*p == 'y');

struct s {
int length;
char data[]; //C99の可変長配列メンバ
};

[引数]添え字演算子。0から始まる配列要素へのアクセス。std::vectorやstd::array等でもオーバーロードされ使用できるが境界チェックのあるat()メンバ関数の方がおすすめ。regexのmatch_resultsではマッチした表現に対応するsub_matchを返す([0]はマッチした全体、[1]以降がキャプチャ部分)。boost.spirit、xpressiveにおいて[]はsemantic action等を記述するために用いられる。C++20のchronoでは第何曜日を表す Sunday[2] //第2日曜日。C++23から,で区切って複数の引数を取れるようになる。

int v = p[3][4]; //二次元配列の3行4列目の値をvに代入
char x = "abcdefg"[3]; //xには'd'が代入される

map系コンテナ変数[キー]std::map系コンテナにおける添え字のオーバーロード。要素へのアクセスだがコンテナにこのキーが存在しないとキーが新たに挿入されて要素が構築される。at()メンバ関数のほうが通常の配列の添え字[]に近い。

std::unordered_map<std::string, std::string> week_dictionary;
week_dictionary["Sunday"] = "日曜日";
week_dictionary["Monday"];
assert(week_dictionary.size() == 2);

整数[配列変数]配列要素へのアクセス。トリッキーな書き方。配列変数[整数]の表記と同じ。

int v = 2[p]; // int v = p[2];に同じ
int v = *(p+2); //これも同じ

delete []配列版delete演算子。動的配列の解放。new T[]とセットで使う。new Tにはdelete P を使用し、new T[]にはdelete [] Pを使用しなければならない。しかしながら様々な安全上の理由からスマートポインタを使う方が良い。そもそも動的配列ならばstd::vectorがおすすめ。

//動的配列の確保と解放(極めて問題が発生しやすい。
// まずはstd::vectorを検討したほうがよい)
auto* p = new int[5]; //値初期化されない
delete [] p;

[[属性]]属性を指定する。もしくは将来のC++においてコントラクトを表し事前事後条件などを指定できるようになるかも。「,」で区切ると複数の属性を指定できる。属性のトークンには ::、()、[]、{}が現れる。C++17よりusing 属性名前空間: で表記の省略ができる

//この関数の使用は推奨されない
[[deprecated("too old")]] void SomeFunction(int x, int y);
[[using gcc: pure, cold]] int func(); //[[gcc::pure, gcc::cold]]と同じ
[[assume(x > 0)]]; //C++23 xが正であることを仮定して良いとコンパイラに伝える。最適化用
void f(int x) [[expects: x > 2]]; //(もしかしたら将来のC++において)引数が2以下の場合既定でプログラムが終了

auto 略[名前, 名前]右辺の構造体から個別のメンバを受け取り新しい変数を宣言する(構造化束縛)。std::tieをより簡単にしたもの。(C++17)

std::map<T,U> m;
auto const [ pos, done ] = m.insert(v);
// insert()の戻り値 std::pair<iterator,bool>を受け取り
// std:map::iterator const pos = ...;
// bool const done = ...; の2変数が宣言される
if(done) {
}

[キャプチャリスト](仮引数リスト) mutable ->戻り値型 { いろいろ }ラムダ式(即席の関数オブジェクト)。キャプチャリストと(仮引数リスト)とmutableは不要な場合に省略可。->戻り値型は場合により省略可。キャプチャリストにはthisや後述の&=が現れる。C++17では*thisがクラス自体のコピーに使える。キャプチャした変数の寿命には注意が必要。C++20では<>で通常のテンプレート関数のようにパラメータリストを指定可能になる予定。

//int値を引数に取り3を足して返すラムダ式 の変数fを宣言
auto f = [](int a) { return a + 3; };
assert( f(2) == 5 ); // f()でラムダ式を呼び出す
[](){}(); //何もしないラムダ式を作り、最後の()でこれを呼び出す

[]<class T>(T a){}; //C++20

auto 関数名(仮引数リスト) -> 戻り値型戻り値型を後ろに記述する関数宣言。C++14なら「-> 戻り値型」は型が推論可能な場合は省略可。「関数名」の部分が「(*名前)」だと関数ポインタ型を表す。「関数名」の部分が「(&名前)」だと関数への参照型を表す。「名前」の部分は場合により省略可。

auto func(void) noexcept -> int {
return 0;
}

template <略> クラス名(仮引数リスト) -> そのクラスの具体的な型;推論ガイド。テンプレートクラスのテンプレート引数をコンストラクタから推論する際に複雑な推論を可能にするためのもの。簡単に推論可能な場合は特に必要ない。(C++17)

//template <class T> struct LockGuard {
//    tempate <class ...Args> LockGuard(Args... args){ /**/ }
//};

template <class ...Args>
LockGuard(Args...) -> LockGuard<std::common_type_t<Args...>>;

//LockGuard<decltype(lock1),decltype(lock2)> g(lock1, lock2);//これが
LockGuard g(lock1, lock2); //こう書ける

requires (引数リスト){式 や 型; }Conceptsのrequires式(C++20)。{}内の式や型が有効であることを要求する。有効であればrequires式はbool値としてtrueをそうでなければfalseを返す。要件の式や型は複数含めることができ、下記の複合要件も使用できる。(引数リスト)は不要であれば省略可。

// ある型Tにはiteratorという内部の型が必要なことを
// 表すコンセプトCを定義
template <class T>
concept C = requires (T t) { typename T::iterator; };

constexpr {式} noexcept -> 制約;上記requires式中の複合要件。{式}は中の式が有効であることを要求する。「->制約」は式がこの制約を満たすことを要求する。「constexpr」は「式」がconstexprであることを要求する。noexceptは「式」がnoexceptであることを要求する。「->制約」「constexpr」「noexcept」はそれぞれ要求しない場合は不要。

// ある型Tを*で間接参照することができ、その間接参照した型が
// intへ変換可能である必要があることを表すコンセプトCを定義
template <class T>
concept C = requires (T t) {
    {*t} -> std::convertible_to<int>;
};

クラスへのポインタ変数 -> メンバアロー演算子。ポインタを経由してのメンバ関数やメンバ変数へのアクセス。下記のドット演算子と間接演算子を用いた「(*クラスへのポインタ変数).メンバ」の表記に普通は等しい。

std::unique_ptr<std::string> p(new std::string());
p->append("hello");

//xがテンプレート仮引数でそのテンプレートメンバ関数funcを使う場合
x->template func<int>(); //templateを途中に挟み文法の曖昧さを解決

クラス変数 . メンバドット演算子メンバ関数やメンバ変数へのアクセス。

std::pair<bool, int> p,q;
p.first = true; //pのメンバ変数firstにtrueを代入
p.swap(q); //pのメンバ関数swapを呼び出す。その際の引数はq

x.template func<int>(); //上記アロー演算子の例を参照のこと。

.小数点。後述の「小数点を含む数値」項目も参照。

9.8
.5 // 0.5
-6. // -6.0
.7E+2f // 0.7 × 10の+2乗 のfloat型 つまり 70.0f

{ .メンバ変数 = 値, .メンバ変数 = 値 }C99(C++20で導入予定だがC99より制約がある)の機能で構造体のメンバ名を指定して初期化できる(designated initializer)。[]を用いると配列を初期化する場合にその要素位置を指定できる。gcc拡張では member:val も同じ意味で使え、[index] val や [index] = val で指定した位置の要素を初期化でき、その位置も [from ... to] として範囲で指定できる 。

type identifer[5] = { [要素位置].メンバ変数 = 値 };

クラス変数 .* メンバポインタメンバポインタを使用した直接のメンバアクセス。メンバ関数を呼び出す場合は (クラス変数.*メンバポインタ)(実引数)のように()で括る必要がある。

クラス変数へのポインタ ->* メンバポインタ
メンバポインタを使用したポインタ経由のメンバアクセス。メンバ関数を呼び出す場合は (クラス変数へのポインタ->*メンバポインタ)(実引数)のように()で括る必要がある。

変数型 クラス名 ::* 名前
「名前」を省略した形が クラスのメンバ変数へのポインタ型(メンバ変数ポインタ型)を表す。「名前」を付ければその変数の宣言。typedefで使えば「名前」はその型の別名となる。

戻り値型 (クラス名 ::*名前)(仮引数リスト)
「名前」を省略した形が クラスのメンバ関数へのポインタ型(メンバ関数ポインタ型)を表す。「名前」を付ければその変数の宣言。typedefで使えば「名前」はその型の別名となる。

struct s {
void func();
};
void (s::*identifer)() = &s::func;
s obj;
(obj.*identifer)();// 上記の .* を使用してメンバ関数呼び出し

...C言語由来の可変長引数。型安全ではないため注意を要する。呼び出すときに小さい型はint/unsigned intへ、floatはdoubleへ変換される。オーバーロード解決の際の優先度は最低である。

int printf(const char* format, ...);
int printf(const char* format...); //上に同じ( ,は必要ない)

...関数風マクロの可変長引数。

// 引数は__VA_ARGS__で展開する
#define MACRO_F(...) func(__VA_ARGS__);
// MACRO_F(1,"a") と書くと func(1,"a") に展開される

...可変長テンプレート、またはそのパラメータパックの展開、C++17において()と特定の演算子と共に用いてfold式を表す。

f(1, 2.0); //こう呼び出すと

template <class... T> //Tは可変長テンプレート
void f(T... args)
// argsはTのパラメータパックでint型の1, double型の2.0を含む
{
 g(args...); // パラメータパックを展開してg(1, 2.0);と呼び出す
 h(std::to_string(args)...); //こんな展開も可能
 //h(std::to_string(1), std::to_string(2.0));に同じ
 typedef boost::mpl::vector<T...> type; // <int, double>と展開

 ( ... + args); // ((1) + 2.0) と左から畳み込むfold式
 (args + ... + 3); // (1 + (2.0 + 3)) 初期値に3を指定して右から

 //ラムダ式のキャプチャリストで可変長の宣言ができる(C++20)
 [...xs = args]{};
}

//ラムダ式の可変長テンプレート (C++14のgeneric lambda)
[](auto... a){};
//C++20ではテンプレート関数をラムダ式と同じ簡略表記で書ける
void k(auto... a){};

//(C++20)コンセプトCを...と以下のように組み合わせると
template <C<short>... T> struct S{};
// requires C<T1,short> && C<T2,short> && ... のように制約が掛かる 

template <class...T>
void j(T......) {}
//可変長テンプレートとC言語由来の可変長引数を組み合わせた形
//前のT...が可変長テンプレートで後の...がC言語由来の可変長引数
void j(T... , ...) {} //これと同じ

template <typename... Bases>
class Derived : Bases... { //多重継承できる
 using Bases::Func...; //複数の派生元に共通の関数をusing宣言できる(C++17)
};

sizeof...(可変長テンプレート)可変長テンプレートパラメータまたはそのパラメータパックの要素数取得
case 定数 ... 定数:gcc拡張でcaseラベルに該当する値を範囲で指定できる。
catch(...) { }すべての例外を捕捉するcatchブロック。
importもしくはmodule モジュール.サブモジュールC++20のモジュールの宣言 「.」は実際には名前の一部。
importもしくはmodule 略 : パーティション;C++20のモジュールパーティションの宣言
::スコープ解決演算子。スコープを修飾して曖昧さを解決する。属性名前空間を指定する。staticメンバ変数の定義。クラスのインスタンスを作らずにstaticメンバへのアクセス。ADLの回避。仮想関数呼び出しの回避。C++17よりネストしたnamespaceをまとめて記述することにも使える。

::func(); //グローバル名前空間のfuncを呼び出し
std::find(); //std名前空間のfindを呼び出し

struct S {
    static int n; //staticメンバ変数なのでこの宣言は定義ではない
    // 注 C++17からinlineをつけると定義にできる
    static S Foo() { return S(); }
    int Bar() [[gcc::cold]]; //属性名前空間
    typedef float value_type;
};
int S::n; //これがstaticメンバ変数の定義

int S::Bar() { //メンバ関数を分離して定義
    //昔のCfrontでは::の代わりに.が用いられていたとのこと
    return 0;
}

//Sクラス内部のtypedefされた型value_typeを用いて変数aを宣言
S::value_type a = 0.0f; //float a=0.0f;

struct T : S {
 using S::S; //using declarationを用いた継承コンストラクタ
};

using namespace std::tr1; //using directive

void f() {
    S::n = 1; //staticメンバ変数へのアクセス
    auto v = S::Foo();  //staticメンバ関数の呼び出し
}
namespace a::b::c { } 
//namespace a { namespace b { namespace c { }}}と同じ

;セミコロン)文の終わり。for文の区切り(ループ条件を省略すると常に真と評価される)。C++17よりswitchもしくはif(変数の宣言; 条件式)とすることでswitch,if,else節内にスコープを限定した変数の宣言ができるようになり、C++20よりrange-based for文でも利用できるようになる。

//for(変数の宣言; ループ条件; 毎ループ後に評価される式)
for (;;) {} //無限ループ
if (auto a=x; a.val > 0) {} //C++17より 

int i; // int 型の変数iを定義。組み込み型なので値は不定値
auto int i; //ローカル変数を表す昔の記述法
class a; //クラスaの前方宣言。struct、unionも。
struct s o; //構造体s型の変数oを定義。Cの文法。
s o; //上と同じ。
int f(); //関数fの前方宣言(プロトタイプ宣言)
1+1; //式1+1を評価。この例の場合、副作用もなく
//結果も利用していないので特に意味はない
throw; //catchされた例外の再送出

for(要素変数の宣言 : 範囲)(コロン) 範囲for文の区切り。C++20よりfor(変数の宣言 ; 要素変数の宣言 : 範囲)が使えるようになる。

int range[] = {1, 2, 3};
for (auto val : range)
    cout << "#" << val;
//出力 #1#2#3

for (auto obj = func(); auto val : obj.getrange()) {} //C++20

式1 ? 式2 : 式3 条件演算子(三項演算子)。まず式1が評価されtrueならば式2が評価され、falseなら式3が評価されて最終的な結果となる。式2と式3は同じ型(暗黙的に変換できればOKもしくはthrow)である必要がある。C言語では?:の優先順位は代入演算子=よりも高いがC++においては同じであることに注意。

std::string greeting = (english) ? "Hello" : "こんにちは";

式1 ?: 式3gcc拡張で条件演算子の真ん中の式を省略できる。式1 ? 式1 : 式3 に等しい。ただし式1が評価されるのは一度のみ。
ラベル名:ラベル。switch文のcase ラベル: や default:。gotoのジャンプ先。これらのジャンプ箇所において変数の初期化処理を飛び越えないように注意すること。
_Generic(式, 型:式, 略)C++ではなくC11のgeneric selection。最初の式の型に対応する式を予め”型:式”の形で列挙しておきコンパイル時に選択できる。これを利用してC++オーバーロードライクなこと等が可能。
アクセス指定:アクセス指定 public: protected: private: の三種 。structのメンバはデフォルトでpublic:指定、classのメンバはデフォルトでprivate:指定されている。クラス継承のアクセス指定については下記「派生クラスの定義」の項を参照。

整数型 変数名: ビット数
ビットフィールド

struct s {
unsigned flag : 2;
unsigned :0; //ゼロ幅を指定すると前後のメモリアドレスを分割できる
//よってflagとoptはアドレスが別になる
unsigned opt: 3, done: 1; 
unsigned a : 5 = 0; //C++20から初期子が使える
};

コンストラク: メンバ変数名やクラス名(), メンバ変数名やクラス名() { }コンストラクタのメンバ初期化リスト。メンバ変数や基底クラスを初期化できる。また「自身のクラス名(実引数リスト)」となっている場合は委譲コンストラクタ呼び出し。()の代わりに{}で直接リスト初期化もできる。初期化される順序はメンバの定義順でメンバ初期化リストで記述した順ではない。以下の例ではv1が最初に初期化される。また昔のCfrontでは基底クラス名を書かずに()だけで初期化できたとのこと。

struct s {
    s() : v2(0), v1(0) { //デフォルトコンストラクタ v1,v2を初期化
    }
    s(const char* p) //const char*を引数に取るコンストラクタ
      : s() //(上で定義したものを)委譲コンストラクタとして呼び出し
    { cout << p; }
    int v1;
    int v2;

    s(double d) try : s() //関数tryブロックを組み合わせた形
    {
    } catch (...) {
    }
};

classかstruct クラス名 : virtual アクセス指定 継承元クラス, virtual アクセス指定 継承元クラス { };派生クラスの定義。アクセス指定やvirtualやクラス名は必要に応じて付ける。structはデフォルトでpublic継承、classはデフォルトでprivate継承される。

struct derived : public base {
};

enum classかstruct 名前 : 整数型enumの基底型を指定する。class、structはscoped enumにする場合。名前は不要な場合は省略可。

enum week : short int { Sunday, Monday, Tuesday, };

*アスタリスク)乗算演算子
ちなみにべき乗の演算子は標準には存在せず、代わりにstd::pow関数が利用できるが浮動小数点数での計算となることに注意。

assert( 3*5 == 15 );

型名*ポインタ型。常に参照先のオブジェクトの寿命に注意が必要。

int d = 0; //int型
//p は d へのアドレスを格納するポインタ型
int* p = &d; 
//q は p(int*型) へのアドレスを格納するポインタ型
int** q = &p; 
// d,p,qの変数自体のアドレスがそれぞれ100,112,116だとすると
// pが格納している値は100、qが格納している値は112になる。

int v = 0;
int* i = &v;
auto  x = i; // x は int* 型
auto* y = i; // y も int* 型
//autoだけでも良いが * を付けてポインタ型であることを明示してもよい

//cv修飾子(constやvolatile)は*との位置関係によって修飾先が異なる
int const * r = i; //rが指している先は変更できないがr自体は変更可
int * const t = i; //tが指している先は変更可、t自体は変更不可
r = nullptr; //OK
t = nullptr; //ill-formed
*r = 1; //ill-formed この*は下記の間接参照演算子
*t = 2; //OK この*は下記の間接参照演算子

*ポインタ変数間接参照演算子。ポインタ(イテレータ)の指す先を参照する。スマートポインタやboost.optionalでもオーバーロードされている。

//上記例の続き
int val1 = *p;
int val2 = **q;//ポインタqの指す先を参照し、さらにその先を参照する
assert(val1 == val2);

int* x; //これはポインタ型
{
  int localval;
  x = &localval;
}
*x = 1; //NG  localvalは寿命切れで未定義動作

戻り値型 (*名前)(引数リスト)戻り値型 (引数リスト)というシグネチャを持つ関数へのポインタ。関数ポインタ。場合により名前は省略可。
「名前」部分が名前(引数リスト)という形式の場合は「戻り値型 (引数リスト)という関数へのポインタ」を返す関数宣言となる。

// void (*)(int, int)という関数ポインタ型にnameという型名を付ける
using name = void (*)(int,int); // usingを使用(新しく高機能)
typedef void (*name)(int, int); // typedefを使用

//下記のように関数へのポインタ、配列への参照などを戻り値型にするときは
//外側から挟むように記述するがusingやtypedefを用いたほうがわかりやすい
void* (*(*func)(int, double*))(char*) = nullptr;
//上は下と同じ
using rettype = void*(*)(char*); //char*を引数にとりvoid*を返
// す関数ポインタ型にrettypeと別名をつける
rettype (*func)(int, double*) = nullptr; //int,double*を引数に取
//りrettypeを返す関数ポインタfuncを宣言、定義しnullptrで初期化

型名 (*名前)[整数]型名[整数]という配列へのポインタ。場合により名前は省略可。
「名前」部分が名前(引数リスト)という形式の場合は「型名[整数]という配列へのポインタ」を返す関数宣言となる。
[ *this ]C++17のラムダ式のthisコピーキャプチャ指定。

struct s {
void f() {
  [*this](){ //sのメンバ変数自体をコピーキャプチャするラムダ式。
    value = 1; //このvalueは元のvalueとは別物
  };
  [self = *this](){ self.value = 1; }; //C++14で上記例を実現する場合
  [this](){}; //メンバ変数はコピーされずthisポインタを経由して参照される
}
int value = 0;
};

+加算の二項演算子。正の符号を表す単項演算子。std::basic_stringにおいて文字列を連結する(その他のライブラリでも連結を表す演算子としてオーバーロードされていることがある)。浮動小数点数リテラルの指数の符号。

short val = 1+2; //val == 3
auto a = +val; //正の符号を表す単項演算子。
// + は - ほど意味を持たないが汎整数拡張が行われaはint型になる

//キャプチャのないラムダ式は関数ポインタへ変換できるが
// +を適用することで強制的に変換できる
auto* fp = +[]{ return 1; }; 

auto str = std::string("hello") + " wolrd!"; // str == "hello world!";
1.5e+2; // 1.5 掛ける 10の +2乗

++インクリメント演算子(1加算する)。ポインタ、イテレータを1要素後ろを指すように移動。

int i=0, j=0;
int v = ++i; //前置のインクリメント
// iをインクリメントした後の値がvに格納される
// ここでvは1、iは1
int w = j++; //後置のインクリメント
//jの値をwに格納したあとjはインクリメントされる
// ここでwは0、jは1
int *p = &i;
int x = *p++; // int x = *(p++);と同じ
//xにはpのインクリメントされる前の
//アドレスを間接参照した値が格納される

int y = (*p)++;
// yにはpの参照先の値が格納され、
//後にその参照先の値がインクリメントされる
//p自体は変化しない

-減算の二項演算子。負の符号を表す単項演算子浮動小数点数リテラルの指数の符号。
--ディクリメント演算子(1減算する)。ポインタ、イテレータを1要素手前を指すように移動。
/除算演算子。整数同士を除算した場合結果もまた整数で少数は切り捨てられることに注意。ゼロ除算に注意。boost.filesystemではpathの連結用演算子としてオーバーロードされている。C++20のchronoでは日付を表す 2020y/January/1
//コメント一行コメント。 //から行末までコメントとして無視して解釈される
/*コメント*/複数行対応コメント。古い時代のC言語ではプリプロセッサトークン連結(現在の##)にも用いられた。
%剰余演算子。boost.formatライブラリでは変数を連続して渡すためにオーバーロードされている。別言語のC++/CLIではGC管理されたオブジェクトに対するトラッキング参照(C++のT&に似ている)としても使用される。
=代入演算子、コンストラクタ呼び出し、デフォルト引数、テンプレート仮引数のデフォルト型やデフォルト引数、コンセプトの定義(C++20)

std::string s = "hello"; // コンストラクタ呼び出し(コピー初期化)
// stringコンストラクタでstringの一時オブジェクトが作られてから
// (stringを引数に取る)ムーブ、コピーコンストラクタが呼ばれる。
// だが一時オブジェクトの作成は省略されうる。

s = "world!"; //代入演算子呼び出し
int a, b;
a = b = 0; //右から結合する。結果としてa、bともにゼロが代入される

if (auto v = f()){} // f()の戻り値でvが構築されそのvをifが評価する

void func(int arg = 3); //デフォルト引数

//テンプレートのデフォルト型、デフォルト引数
//下記例の後者はenable_ifを使いSFINAEをするために
//デフォルト型を指定する場所を利用しているだけ。
template <class T = int, 
    class = typename std::enable_if<is_xxx<T>{}>::type>
void g() {}

//autoを使用した場合は初期化値から型が推論される。
auto c = 0.0; //変数cはdouble型

//コンセプトの定義(C++20)
template <class T>
concept ConceptName = std::is_integral_v<T>;

//コンセプトを用いてautoに制約を付加した使い方ができる。(この場合autoは省略可)(C++20)
ConceptName auto d = 0.0; //変数dはdouble型だがコンセプトの制約を
//満たしていない場合コンパイルエラーとなる

[ = ]ラムダ式のコピーキャプチャ指定。およびC++14のラムダ式で新しい変数を宣言する際の初期化子として現れる。

[=, &y](){};//使用するローカル変数は全てコピーキャプチャ。
//ただしyは参照キャプチャ
[x = std::move(v)](){}; //vをムーブしてxという名前で宣言

=名前空間またはテンプレートまたは型の別名指定

namespace 新しい別名 = 名前空間;
using 新しい別名 = 型名;

virtual メンバ関数宣言 = 0純粋仮想関数の宣言
メンバ関数宣言 = default;コンストラクタや代入演算子などの特殊メンバ関数を可能であれば明示的に生成する。C++20から三分比較演算子<=>と ==演算子に =default;指定し他の比較演算子を生成可能。
関数宣言 = delete;関数を明示的に削除されたものとして定義する。
==等値比較。組み込みの比較演算子の戻り値型はbool型。比較演算子を用いて浮動小数点数を比較する際には注意が必要。

assert( 1+3 == 2+2 );

!=非等値比較。C++20からは==が定義されていれば自動生成されるようになる。
>=比較 大なりまたは等値
<=比較 小なりまたは等値
<=>C++20より導入される三分比較演算子(通称 宇宙船演算子)。比較演算に厳密な意味を与え、他の比較演算子(<,>,<=,>=)の自動生成が可能になる。また定義がdefaultedな場合は==演算子が暗黙的に定義される。

struct T {
// 全ての要素を直線的に並べられるられるものはstrong_orderingを返し、
// ==でtrueを返しても実際は異なるもので外部から区別が可能なものが
// ある場合weak_orderingを返し、
//そもそも比較が不適当な要素を含む場合にはpartial_orderingを返すこと。
// strong_ordering の例 整数同士の比較
// weak_ordering の例 英大文字小文字を区別しないクラス
//               'A'=='a'にtrueを返すが isupperなどで区別が可能
// partial_ordering の例 floatのNaNなど比較が不適当な場合
std::weak_ordering operator <=> (const T& rhs) const {
    if( toupper(val) < toupper(rhs.val) ) return std::weak_ordering::less;
    //...
}
char val{};
};

<<=左シフトして代入
>>=右シフトして代入
+=加算して代入。std::basic_stringにおいては文字列を追加する。

int i=5;
i += 3; //左辺と右辺を加算し、その結果を左辺に代入する
assert(i == 8);

std::string s = "Hello";
s += " World!";
assert(s == "Hello World!");

-=減算して代入
*=乗算して代入
/=除算して代入。boost.filesystemのpath、property_treeのstring_pathでは連結代入用演算子としてオーバーロードされている
|=ビットORして代入
&=ビットANDして代入
%=剰余を代入
^=ビットXORして代入
!(エクスクラメーションマーク) 論理否定演算子。また型変換演算子 operator ポインタ型()等とともにオーバーロードされオブジェクトの状態をbool値として調べることができるようによく利用される。ただしこれはC++11以降ではexplicit operator bool()だけで事が足りるようになった。変わったオーバーロードがされていなければ「!!式」とすれば明示的に式をbool値へ変換できることになる。
C++23では if ! consteval として if consteval の否定として使える。

bool result = !true;
assert(result == false);

!クラスと同じ名前()クラス内でデストラクタと同じように宣言されている場合は別言語のC++/CLIにおいてファイナライザを表す。そうでなければ単にクラスのインスタンスを作成して論理否定演算子を呼び出しているだけだろう。
^(ハット、サーカムフレックス) ビットXOR。
別言語のC++/CLIではGC管理されたハンドル(C++のT*に似ている)を表すことにも使用される。

unsigned value =  x ^ 0b00000100; //xの下から3bit目をビット反転させる

&ビットAND

unsigned value =  x & 0xFF; //下位8bitを取り出す

&&論理積。左の式が偽なら右の式は評価されない。ただしオーバーロードされている場合は両方の式が評価されさらにその順序は不定

if (x == 1  && y)
  puts("xは1と等しく尚且つyをbool値として評価するとtrueであった");

&変数や関数アドレス演算子。変数や関数のアドレス取得。ただしオーバーロードされて別の意味になっている場合もありえるので確実を求めるならstd::addressof関数が利用できる。

int x=0;
int* ptr = &x;

&&ラベル名gcc拡張でラベルのアドレスを取得する。
型名&左辺値参照(単に参照といえば普通はこれ)。宣言する場合は初期化が必須(externを除く)。constな参照は一時オブジェクトを束縛してその寿命を参照と同じ期間まで延長できる。クラスのメンバに持たせるとデフォルトの代入演算子が使用できなくなる。常に参照先のオブジェクトの寿命に注意が必要。関数の戻り値型としてはオブジェクトの寿命について理解していない限り使用すべきではない。

//別名を付ける
int i=0;
int& j=i;
i=2;
assert( j == 2 );

//関数仮引数として使う一般的な使用例
void func1(const std::string& s) { cout << s << endl; }

//一時オブジェクトの束縛。ただし必要となる場面はあまり無い。
int const& read_only_integer = int(); //OK

//一時オブジェクトは直接でないと束縛できない
auto const& r = *make_unique<int>(); // NG
// すでに参照先は寿命切れで r を使うと未定義動作

std::string& func2() { // 未定義動作につながる
  std::string str("hello");
  return str; // NG 非staticローカル変数strの寿命はここまで
}

const int& func3(const int& i) {
 return i;
}
const int& r = func3(1); // NG 直接でないと束縛できない
// 整数リテラルは一時変数であり完全式の終わりですでに破棄済み

void alloc_int(int*& r) { //int* への参照
r = new int(0);
} 

型名&&右辺値参照。しかしながら型名がauto&&の場合や関数テンプレートの仮引数においてそのテンプレートパラメータ型&&の場合に左辺値が渡されると型名&&は左辺値参照に推論される(Forwarding References)。つまりForwarding Referencesで受けた変数は無条件にstd::moveできない(代わりにstd::forwardを使う)。上記左辺値参照の項目の注意点も参照せよ。右辺値参照の場合constが付いていなくても一時変数を束縛できる。

//一時オブジェクトなど右辺値のstd::stringのみ受け取れる
void func1(std::string&& t) { 
}
//どんな型の右辺値、左辺値でも受け取れる
template <class T>
void func2(T&& t) {
}

戻り値型 (&名前)(仮引数リスト)戻り値型 (仮引数リスト)のシグネチャを持つ関数への参照。名前は場合により省略可。
「名前」部分が名前(引数リスト)という形式の場合は「戻り値型 (仮引数リスト)の関数への参照」を返す関数宣言となる。
型名 (&名前)[整数]型名[整数]という配列への参照。名前は場合により省略可。
「名前」部分が名前(引数リスト)という形式の場合は「型名[整数]という配列への参照」を返す関数宣言となる。

template <class T, size_t N>
void f(T (&arr)[N]) {
    cout << N << endl; //テンプレートを用いることで配列長を得ることが可能
}

int a[10];
f(a);

[ & ]ラムダ式の参照キャプチャ指定

[&y]{}; //yを参照キャプチャ
[&, v]{}; //使用するローカル変数を全て参照キャプチャ。
//ただしvはコピーキャプチャ。

メンバ関数宣言 &この関数はクラスのインスタンスが左辺値のときのみ呼べる。

struct s {
void f(int) & {}
};
s v;
v.f(0); //OK vは左辺値
s().f(0); //ill-formed s()は右辺値

メンバ関数宣言 &&この関数はクラスのインスタンスが右辺値のときのみ呼べる。rvalue reference for *this
|バーティカルライン)ビットOR。boost.rangeライブラリではアダプタを適用するパイプ演算子としてオーバーロードされている。

assert((0b1100 | 0b0011) == 0b1111);

||論理和。左の式が真なら右の式は評価されない。ただしオーバーロードされている場合は両方の式が評価されさらにその順序は不定
requires 式 && もしくは ||requires節(C++20)において制約を複数個指定する。通常の論理積論理和と使い方は似ている。通常の論理積論理和を使う場合は()で括ること。

// UがコンセプトC1を満たすかもしくは整数であれば制約を満たす関数を定義
template <class U>
requires C1<U> || std::is_integral_v<U>
void func(U) {}

,カンマ演算子。前から順に評価される。しかしながらオーバーロードされている場合に評価順序は不定。また下記項目の関数引数の区切りの評価順序は不定で混同に注意が必要。全体を()で括らないと基本的に変数や関数の複数宣言と解釈されてしまうため括るべき。

auto v = (f(), g(), h());
//f(),g(),h()の順に呼び出され最後のh()の戻り値がvに代入される

// 応用例としてmutexのlock、unlockがワンライナーで記述できる
// まずlock_guardの一時変数が作られコンストラクタでmtx.lock()が
// 呼ばれ次に flag = trueが評価され、そのあと完全式の終わりに
// lock_guardのデストラクタが呼ばれそこでmtx.unlock()が呼ばれる
(lock_guard<mutex>{mtx}, flag = true);
((lock_guard<mutex>)mtx, flag = true);

template <class T>
auto k(T t) -> decltype(t.size(), t.front(), std::declval<void>());
//SFINAEをする目的でdecltypeの中で用いてt.size()と
//t.front()が有効な時だけ関数kが使えるようになる。
//decltype中の式は実際には評価されない。
//関数kの戻り値は最後のdeclval<void>()からvoidとなる。

,関数引数リストの区切り。引数の評価順序は不定でsequenced beforeの関係もこれだけでは入らないことに注意。

func(f(), std::unique_ptr<int>(new int)); //bad
// f(), unique_ptr(), new intの評価順序は不定
// ただし new int は unique_ptr() よりは前に呼ばれる

// 仮に new int、f()、unique_ptr()の順で呼び出されるとすると、
// f()が途中で例外を投げた場合は new intで確保された領域が
// リークすることになる 

// そこでnewを直接使用せずmake_uniqueを使用する
func(f(), std::make_unique<int>()); // OK

// 若しくは一旦スマートポインタに名前を付けるとよい。
std::unique_ptr<int> p(new int); //すぐにunique_ptrを構築
func(f(), p); //OK

,単にリストの区切りとして用いられる。初期化リスト内の要素の区切り(前から順に評価される(g++4.9.1未満は不定))。継承元クラスの複数指定(多重継承)、列挙型(enum)の列挙子を定義する際の区切り、(テンプレート)仮引数リストの区切り、関数風マクロ引数リストの区切り、ラムダ式のキャプチャリストの区切り、属性の複数指定、構造体束縛の変数名の区切り。
型名 名前, 名前;変数や関数の複数宣言。個別に型を記述した場合と同じ。int* x, y;と記述した場合xはint*型、yはint型になる。yもint*型にするには int* x, *y;と記述する。参照の&も初期化が必須なこと以外同様。

int v=0,w,*x,y{}, *(*z)(), a();
// int v=0; int w; int* x; int y{}; int* (*z)(); int a(); に同じ
// int a(); は関数宣言であることに注意

~チルダ)ビット否定。gcc拡張で__complex__もしくは_Complex型の複素共役を求める。全ビットを1にするために = ~0u を使用するのは汎用性がないため = -1 の方が良い。
~クラスと同じ名前()クラスのメンバ関数として宣言されているならデストラクタ宣言。メソッドとして呼び出されているならデストラクタの明示的な呼び出し(配置newとセットで使う)。それ以外なら単にクラスのインスタンスを作成してビット否定演算子を呼び出しているだけだろう。
<比較 小なり

int x = 1;
assert(x < 2);

>比較 大なり
<<左シフト演算子。ストリームクラスではオーバーロードされ、ストリーム出力に使用される。

unsigned x = 1u << 8; //1を8bit左シフトする。x=256
std::cout << "result:" << x; //標準出力に「result:256」と出力

>>右シフト演算子。ストリームクラスではオーバーロードされ、ストリーム入力に使用される。
<テンプレート引数リスト>テンプレート型の定義、テンプレート引数の指定、テンプレートの特殊化。またC++14以降の変数テンプレート。C++20のコンセプト。C++20ではラムダ式にも現れる。コンセプト名をclassやtypenameの代わりに記述することで制約を付加できる(C++20)

template <class T = void> struct S { };
template <> struct S<int> { }; //Sをint型に特殊化
// 最初の<>はSのテンプレート引数を全て特殊化したため空になっただけ

template struct S<std::string>; //Sをstd::string型で明示的にインスタンス化

std::vector<double> v;
S<> a; //テンプレート引数を省略した形

template <class T>
T Val{}; //変数テンプレート
Val<int>; //これは型ではなく値

template <auto v> //非型テンプレート (C++17)
struct s{};
s<3> o;
//非型テンプレートに制約を付加する場合(C++20)は
template <ConceptName auto v>となる

static_cast<型名>(値)キャスト。static_cast、const_cast、dynamic_cast、reinterpret_castの4種。これらのキャストを利用しても元々未定義動作をするコードが安全になるわけではないことに注意。

const int a = 1;
*const_cast<int*>(&a) = 2; // 未定義動作

#include <ファイル名>include命令。指定されたファイルを読み込んでこの位置に貼り付ける。<>の代わりに""で大抵の場合代用可能だが<>は主に処理系の提供するヘッダや他のライブラリを読み込むのに使用される。C++17より__has_include()内に<>と""も現れる。
関数名<<<実行コンフィグ>>>(引数リスト)CUDA拡張でカーネル関数を呼び出す。
()
式の結合順序を指定。2*(3+4)など。結合順序が変わらなくても順序を明示してコードを読みやすくしたり、単に見た目を改善するために使用されることもしばしば。関数風マクロの仮引数は意図しない解釈のされ方を少しでも防ぐため必ずと言っていいほど()で囲まれる。#define MACROFUNC(a) ((a)->member)
文法の曖昧さを解決するためにも用いられる。template <bool A = (1 > 0)>

関数名を囲い意図しない関数マクロの展開を防ぐことにも用いられる。maxというマクロが定義されている環境で競合を回避してテンプレート関数のstd::maxを使用するには(std::max)(1,2);のようにする。ADLの回避にも使用可。関数風マクロに渡す引数に「,」が含まれていると関数風マクロの区切りと解釈されてしまうのでその回避にも使用可能(ただし()がそのままトークンに残る)。MACROF((arg1<int,char>{}), arg2);

通常の関数の実引数として使用した場合は()内の,はカンマ演算子となる。
f((1,2), 3); //最終的にf(2,3);となる

またdecltype( )ではさらに内側に()があるかどうかにより挙動が異なる場合がある。内側の括弧が無くeが識別子かメンバアクセスの場合にdecltype(e)はeの実体の型となる。それ以外の場合で例えばdecltype( (e) )ではeがxvalueなら右辺値参照型、eがlvalueなら左辺値参照型となり、それ以外ならeの型となる。このルールはC++14においてdecltype(auto)を使用した変数の宣言や関数の戻り値型推論でも同様。つまり初期化の式やreturn文の式が()で囲まれているかどうかによって型推論の結果が異なる場合がある。

C++17においてテンプレートパラメータパックと「...」と特定の演算子を共に用いてfold式を表す。

 int x=0;
 decltype(auto) y = x;   // int 型
 decltype(auto) z = (x); // int& 型
 int& r = x;
 decltype(auto) s = r;    // int& 型

decltype(auto) func() {
 int a = 1;
 return (a); //NG int&型となりdangling referenceとなる
}

キーワード等 (条件など)キーワード部分には if、if constexpr、for、while、switch、sizeof... 、alignof、alignas、typeid、decltype、catch、throw、noexcept、new、new auto、static_assert、asm、explicitなどが当てはまりカッコ内にその条件、型、変数などを記述する。gcc拡張で属性を使用するには __attribute__ ((属性)) のように二重に括弧が必要。

if (x != nullptr) {
 new (x) int{}; //配置new (注意が必要な機能)
 auto ip = new (std::nothrow) int{}; //失敗すると例外を投げずに
 //ヌルポインタ値を返す
 auto dp = new auto (0.0); //初期化値から型を推論してnew
 void* vp = operator new (8); //指定したサイズの領域を確保するだけ
}
// new (Arg1, Arg2) T という文法は内部で
// operator new (sizeof(T), Arg1, Arg2)を呼び出す

関数名(実引数リスト)関数呼び出し、関数呼び出し演算子の呼び出し。関数風マクロの展開も同じ形。「関数名」は関数ポインタまたは関数への参照または関数オブジェクトでもよい。

{
f(); //fが関数名、関数ポインタ、関数への参照の場合は 関数呼び出し
g(); //gが関数オブジェクトの場合は 関数呼び出し演算子の呼び出し
h(); //hが型名の場合はこれは関数呼び出しではない(オブジェクトの構築)
k(); //C89以前のC言語の場合 関数呼び出しだがkが宣言されて
       // いない場合に暗黙的に int k();が宣言されることに注意。
       // 関数の外にあるならこれは関数呼び出しではなく int k();の宣言

std::vector<int> v;
v.push_back(0); //vectorクラスのpush_backメンバ関数の呼び出し

auto neg = std::negate<int>()(1); // 前者の()はオブジェクトの構築
//後者の()は構築された関数オブジェクトの関数呼び出し演算子の呼び出し
}

戻り値型 関数名(仮引数リスト)関数宣言。

int sum(int a, int b);
int sum(int,int); //単なる宣言や変数を使用しない場合は
//仮引数は型だけでもよい
auto sum(int a, int b); // C++14以降なら場合により可(->の項も参照)

//(C++20)コンセプトで引数に制約を掛けたテンプレート関数の簡略表記
void f(SomeConcept auto arg){} 

戻り値型 (仮引数リスト)戻り値型 (仮引数リスト)というシグネチャを持つ関数型。std::result_ofに渡す場合は違った意味として解釈され、「戻り値型」部分は呼び出し可能な型として扱われる。result_ofのように関数型を本来の意味から外れて単なる型リストとして扱うこともしばしばある。

//戻り値が int で引数が void の関数などを格納できる
std::function<int()> funobj;

struct st{
	char operator ()(double d);
};
std::result_of<st(double)>::type val1; //char型

int f(void*) { return 0; }
//普通の関数をresult_ofに渡すには参照型にする必要がある
std::result_of<decltype(f)& (void*)>::type val2; //int型

(this 型名 仮引数)C++23のdeducing this。メンバ関数もしくはラムダ式の仮引数として呼び出し元のインスタンスを明示的に取得できる。
これによってconst修飾子、ref修飾子の有無などの違いを統一して一つの関数として記述することが可能となる。また再帰ラムダの記述を簡素にできたりするその他の恩恵もある。

struct S {
template <class T>
void f(this T&& self, string str) {
    if(is_const_v<remove_reference_t<T>>) {}
}
};
S{}.f("Hello"); // 仮引数selfにはこのS{}が渡される。
// 実引数の"Hello"は2番の仮引数strに渡る。

new 型名(実引数リスト) または {実引数リスト} new演算子。動的にオブジェクトを構築してそのポインタを返す。初期化の注意点については下記項目を参照。C++14以降からstd::make_uniqueが使用できるので直接newを使用することなるべく避けたい。C++11以前でもスマートポインタと組み合わせて使う。new,deleteを手動で管理するのは極めて問題が発生しやすい。

p=new std::string; //デフォルト初期化されコンストラクタが呼ばれる
q=new int; //デフォルト初期化され組み込み型なので値は不定値
r=new int(); //値初期化される

型名 変数名 (実引数リスト) または {実引数リスト} または = {実引数リスト}コンストラクタを呼び出してインスタンスを作成する。上記関数宣言の形式と区別がつかない場合は関数宣言と見なされる。()の代わりに{}={}を使用してリスト初期化する場合は空の場合を除いてstd::initializer_list<>を引数に取るコンストラクタが優先されるので注意。下記の初期化リストの項目も参照。C++20から集成体初期化が()でも行えるようになった。

std::vector<int> a(5); //vector(size_type)を呼び出し
//aは値が0の要素を5個含むvector
std::vector<int> b{5}; //vector(initializer_list<int>)を呼び出し
//bは値が5の要素を1個含むvector
int c1; //c1はデフォルト初期化され組み込み型なので不定値となる
int c2{}; //c2は値初期化されて0となる
int c3(0); //c3は0で初期化される
std::vector<int> d; //デフォルトコンストラクタ呼び出し
std::vector<int> e{}; //デフォルトコンストラクタ呼び出し
std::vector<int> f();//std::vector<int>が戻り値型で
//引数リストが空の関数宣言と見なされる

int g((int())); // int g; を宣言し値0の一時オブジェクトで初期化
int g(int()); // int g(int (*)()); という関数宣言と見なされる

int ar[](1,2); //集成体初期化(C++20)

型名(実引数リスト) または 型名{実引数リスト}関数形式の明示的な型変換。(必要であれば型の変換を行ったり)コンストラクタを呼び出すなどして一時オブジェクトを作成。()の代わりに{}を使用する場合は上記の注意を参照。C++23からauto(値)が使えるようになる(decay-copy)。

auto s = std::string("abc") + "defg";
auto v = int() * 1; // 組み込み型のintは値初期化され0となる

型名(宣言子)宣言子が()で囲まれている宣言。上記の関数形式の明示的な型変換と区別がつかない場合はこちらの宣言として解釈される。

T(a);
T a; //上はこれと同じ

//doubleを引数にとりintを返す関数ポインタ型のnameという名前の変数
int (*name)(double); 
//doubleを引数にとりint*を返すname関数の宣言
int *name(double); 

クラスと同じ名前(仮引数リスト)コンストラクタの宣言。上記「:」のコンストラクタのメンバ初期化リストの項目も参照。

class S {
public:
S(); //デフォルトコンストラクタ
explicit S(int i); //1引数のコンストラクタはexplicitを付けることを検討せよ
S(const S& rhs); //コピーコンストラクタ
S(S&& rhs); //ムーブコンストラクタ
~S(); //デストラクタ
S& operator = (const S& rhs); //コピー代入演算子
S& operator = (S&& rhs); //ムーブ代入演算子
};

(型名)変数型のキャスト(コンストラクタの呼び出し、型変換演算子の呼び出し)。キャストにはstatic_cast<>等の新形式のキャストを使用すべき。

(void)func(); // void型へのキャストで戻り値を使用しないことを明示。
// unused variableの警告消しにも (C++17より
// [[maybe_unused]]属性が利用可)

関数宣言 throw(型リスト)古い形式の動的例外指定。この関数が投げうる例外を指定する。主にthrow()として例外を投げない表明として用いられていたが現在ではnoexceptを使用したほうが良い。

void f1() throw(); //古い形式の例外を投げない表明
void f2() noexcept; //例外を投げない表明
void f3() noexcept(true); //trueなら投げない、falseなら投げうる表明

structかclassまたはunion 中略{ いろいろ }中略;クラスまたは共用体の定義部分。最後の;は必須。最後の中略部分は必要に応じてこの型(もしくはそのポインタ型など)の変数を定義できる。またはtypedef structの形なら別の型名を付けることができる。C言語においてはtypedefを用いると型を宣言するたびにstructキーワードを使う必要がないので利便性が向上する。

struct s { int v; } *ptr, obj, arr[] = {0, 1, 2};
//上は下と同じ
struct s { int v; };
s* ptr;
s obj;
s arr[] = {0, 1, 2};

enum 中略{ 列挙子, 列挙子=定数式, }列挙型の定義部分。=で値を割り当てられる。割り当てないと最初の列挙子の場合は値が0になり、それ以外の列挙子は前の列挙子の値に1加算した値となる。
{ 値, 値, 値 }初期化リスト。集成体の初期化、コンストラクタ呼び出し。std::initializer_list<要素の型>型にもなる(要素の寿命に注意)。配列やコンストラクタの無いクラスのメンバを初期化するときに省略された要素は値初期化される。staticメンバや匿名ビットフィールドは飛ばして無視される。またリスト内の式は前から順に評価される(g++4.9.1未満は不定)。narrowing conversionはできない。

struct s { int x,y,z; }; //この{};は構造体の定義
s a;   //x,y,zは不定値
s a{}; //x,y,zは0で初期化される
s a = {}; //同上
s a = {0}; //結果として同上
s a = {1}; //x=1,y=0,z=0
s a{1};  //同上

struct t {  //この{};は構造体の定義
 int x,y,z=1;
 std::string str;
 t():x(0){} //この{}はコンストラクタ本体
}; 

//以下のいずれの場合もコンストラクタが呼ばれる
t a; // x=0, yは不定値, z=1, strは適切に初期化される
// xはメンバ初期化リストで初期化されているため
// zはデフォルトメンバ初期化子で初期化されているため
// strはstd::string型自体が適切なコンストラクタを持っているため
t a{}; //同上
t a={}; //同上

struct u {  //この{};は構造体の定義
int x,y,z;
u(std::initializer_list<int> il) { //この{}はコンストラクタ本体
 for(auto v : il) cout << v;
}
u(int a, int b, int c) {} //この{}はコンストラクタ本体
};

u a{ 0, 1, 2 }; // std::initializer_list<int>を
// 引数に取るコンストラクタが呼ばれる
u a={0,1,2}; //同上
u a(0,1,2); //intの引数を3つ取る方のコンストラクタが呼ばれる
//上記のいずれもx,y,zを初期化している箇所がないために
// いずれの場合もx,y,zはすべて不定値

auto x = { 0 }; //xはinitializer_list<int>型
auto y{ 0 }; //yはC++17より挙動が変更されint型になる

//initializer_list<int>を構築。即席の配列として利用
for (auto v : { 2,4,6,8 } ) cout << v;

void func(int);
func({}); //関数引数の型(ここではint)を明示せずに構築

pair<int,int> f() {
return {0, 1}; //戻り値がコピーリスト初期化される
}

{ いろいろ }

ブロックスコープ。関数本体やラムダ式本体の定義部分。for、do、while、if、else、try、catchのブロック。スコープの範囲を抜ける時にローカル変数のデストラクタが呼ばれる。たとえばローカル変数のfstreamやlock_guardを宣言し使用している個所を{ }で囲うことでリソースを扱う部分を局所化し、早期にファイルやロックを解放できたりする。

またswitch文ではなるべく{}でスコープを導入しローカル変数を宣言する場合はさらに内側に{}でスコープを作りcase、defaultラベルを跨がないようにするべき。

void f() {
  std::string str;
  {
    std::ifstream file("path");
    file >> str;
  } //ここでfileのデストラクタが呼ばれファイルが解放される
  std::cout << str;
} //ここでstrのデストラクタが呼ばれる

namespaceやextern 中略{ いろいろ }namespaceスコープの指定。もしくはexternで言語リンケージを適用する範囲を指定する。namespace { 略 } で無名名前空間を表す。
({ いろいろ })gcc拡張で複数の文を一つの式として扱える。

int x = ({ int y=0; y+1; }); //xには最後のy+1;の値が代入される

#プリプロセッサ命令(関数風マクロ定義など)。

//関数風マクロを定義
// FUNC(0) がf(0)に置き換わる。
#define FUNC(arg) f(arg) 
# //単独の#に意味はない

#関数風マクロ内でマクロパラメータを""で括り文字列リテラル化する。

//引数paramを文字列リテラル化するTXTという名前の
//関数風マクロを定義 TXT(hello)が"hello"に置き換わる。
#define TXT(param) (#param) 

##関数風マクロ内でのトークン連結。またgcc拡張では ## __VA_ARGS__ とすることでこの可変長引数マクロの引数がゼロ個の場合に手前にある「,」を削除できる。
#@VC拡張でマクロパラメータを''で囲い文字リテラル化する。
小数点を含まない数値intもしくはそれより大きい型の整数リテラル。0以外の数字から始まる場合は10進数だが0から始まる場合は基数が異なる。下の項目を参照。
小数点を含まない数値Uunsignedの整数リテラル。小文字のuも可。下記のLやLL、Zと組み合わせることができる。
小数点を含まない数値Llong intもしくはそれより大きい型の整数リテラル。小文字のlも可。
小数点を含まない数値LLlong long intの整数リテラル。小文字のllも可。
小数点を含まない数値Z(C++23) ptrdiff_t型を表す。Uと組合わせたZUもしくはUZの場合はsize_t型。小文字のz、zu、uzも可。
小数点を含む数値Llong double型浮動小数点数リテラル。小文字のlも可。
小数点を含む数値double型浮動小数点数リテラル
小数点を含む数値Ffloat型浮動小数点数リテラル。小文字のfも可。
小数点を含む数値F16等(C++23) float16_t型浮動小数点数リテラル。その他F32,F64,F128もある。小文字のf16,f32,f64,f128も可。
小数点を含む数値BF16(C++23) bfloat16_t型浮動小数点数リテラル。小文字のbf16も可。
数値E指数浮動小数点数の指数表記(基数は10)。小文字のeも可。
数値il虚数のユーザー定義リテラル。std::complex<long double>型。(C++14)
数値if虚数のユーザー定義リテラル。std::complex<float>型。(C++14)
数値i虚数のユーザー定義リテラル。std::complex<double>型。(C++14)
小数点を含む数値iもしくはjgcc拡張で虚数を表す。1.2fjならfloat _Complex型で虚部の値が1.2となる。
IC99の虚数単位。const float _Imaginary型。
数値df、dd、dlgcc拡張の10進浮動小数点数。それぞれ_Decima32、_Decimal64、_Decimal128型。大文字も可
数値r、k、hr、ullkgcc拡張の固定小数点数。大文字も可
数値q、wgcc拡張の浮動小数点数。大文字も可
数値h、min、s、ms、us、ns時、分、秒、ミリ秒、マイクロ秒、ナノ秒のユーザー定義リテラル。std::chrono::duration型。(C++14)
数値y、dC++20のchronoで西暦年と日を表すユーザー定義リテラル
0x0〜9またはa〜fからなる数値16進数リテラル。大文字の0X、A〜Fも可。

int val = 0x7F; // val == 127

0x数値p指数C++17、C99もしくはgcc拡張で16進数で浮動小数点数リテラルを記述できる。但し指数部分は10進数で底は2。大文字の0XやPも可。

0x1.EP-3f; // (1 + 14/16) * (2の-3乗)のfloat型

0b数値2進数リテラル。大文字の0B数値も可。 (C++14)
0数値8進数リテラル

assert(015 == 13);

0単に0と書いた場合は文法上8進数の零として解釈されていることになる。0はヌルポインタ定数として用いることもできるが、nullptrを使用するほうがよい。特殊な文法としては純粋仮想関数の宣言にも使われる(=0の項目参照)。クラスメンバの宣言部分における 型:0 はビットフィールドのゼロ幅指定で特別な意味を持つ(:の項目参照)。整数の0をbool型に変換した場合はfalse、0以外の値はtrueとなる。
数値途中の'数値途中のシングルクォーテーションマークは数値の区切り。無視して解釈される。 (C++14)


assert(1'234'567 == 1234567);

'文字'文字リテラル。接頭辞が無く単独の文字ならchar型(C言語の場合はint型)、複数の文字ならint型のマルチ文字リテラルLの接頭辞はwchar_t型、uの接頭辞はchar16_t型、Uの接頭辞はchar32_t型。
C++17ではu8の接頭辞でエンコーディングUTF-8を指定できる。
"文字列"文字列リテラル。const char型の配列。文字列リテラルは最後に'\0'が付加される。他のリテラルとは異なり文字列リテラルそのものへのポインタはスコープを超えて持ち回せる。文字列リテラルや文字列へのポインタ同士を==や!=を用いて比較しても文字列の比較とはならない。
"文字列" "文字列"連続した文字列リテラルは連結され一つの文字列リテラルと解釈される。行を跨いで連結することも可能。
extern "C" または "C++"言語リンケージを指定。外部リンケージを持った関数型や関数名、変数に影響する。
#include "ファイル名"include命令。指定されたファイルを読み込んでこの位置に貼り付ける。主にユーザーの用意したファイルを読み込むのに使用される。読み込みに失敗した場合は #include <ファイル名>にフォールバックされる。
L"文字列"ワイド文字列リテラル。const wchar_t型の配列。
u8"文字列"エンコーディングUTF-8の文字列リテラル。const char型の配列。
u"文字列"char16_t文字列リテラル。const char16_t型の配列。
U"文字列"char32_t文字列リテラル。const char32_t型の配列。
R"区切り用文字列(文字列)区切り用文字列"Raw文字列リテラル。区切り用文字列は自由に決めて囲うことができる、省略可。エスケープが不要で改行も見た目のまま表現できる。R接頭辞は上記L,u8,u,U接頭辞と組み合わせることができる。

auto str = LR"(hello
world)";
assert(str == L"hello\nworld"s);

"文字列"sbasic_stringリテラル。"文字列"sならstd::string型、L"文字列"sならstd::wstring型など。(C++14)
"文字列"svbasic_string_viewリテラル。(C++17)
"%02d %f %s"などprintf、scanf系またはstrftimeなどの関数に渡す書式指定文字列。単なる文字列だがこういった関数の中でこれらの記号は特別な意味として解釈される。printfの文法。使用される記号は%.+- 0*#[^]{:}<>=など。scanfではfloatとdoubleの区別をつける必要があるなどその差異に注意が必要。boost.formatでは"%1% %2$d"なども使用される。マクロのPRI〜、SCN〜は inttypes.h ヘッダでdefineされており stdint.hで定義されている型(int8_tなど)をprintf、scanfなどに渡すときに使用する書式。std.formatはPythonに基づく文法(仮)を採用予定。
"^[0-9]+(a|b)?"などregex系のオブジェクトに渡す正規表現。単なる文字列だが正規表現ライブラリでこれらの記号は特別な意味として解釈される。使用される記号は^$[-](|).*+?:{,}\など。std.regexはデフォルトでECMAScriptに基づく文法を採用し、boost.regexはデフォルトでPerlに基づく文法を採用している。
\文字(円記号、英文フォントではバックスラッシュ)文字(列)リテラル内において続く1文字をエスケープする。\'、\"、\?、\\、\a、\b、\f、\n、\r、\t、\vのうちのどれか。例えば\tは水平タブ文字、\\は\に変換される。改行としてUnixでは\n、Windowsでは\r\nがよく用いられる。gcc拡張では\eはASCIIのESCに変換される。

//たとえば c:\folder\document.txt ファイルを開くときは以下のように
std::ifstream f("c:\\folder\\document.txt"); // \を\\にする事が必要
//もしそのまま書いた場合は'\f'がform feed制御文字になってしまう。
//'\d'は解釈できずコンパイルエラーとなるか独自のコンパイラ拡張に
//より何らかの文字へ変換されてそのままコンパイルが通るかもしれない

//ファイルパスはエスケープの必要がない/(スラッシュ)を
//使うのがわかりやすい (C++というよりはOSのTips)
std::ifstream f("c:/folder/document.txt");
//Raw文字列リテラルを使う方法もある。この場合Rと()が必要。
std::ifstream f(R"(c:\folder\document.txt)");

\八進数文字を8進数の文字コードで指定。最大三桁。例えば\0はNUL文字に相当。
\x十六進数文字を16進数の文字コードで指定
\u十六進数UCS-4文字を表す。コードポイントの上位16bitは0000で固定。下位16bitを16進数で指定
\U十六進数UCS-4文字を16進数の文字コードで指定
\o{八進数}(C++23) 文字を8進数の文字コードで指定。\八進数の場合とは異なり桁数に制限がない。
\x{十六進数}(C++23) 文字を16進数の文字コードで指定。\xよりも範囲がわかりやすい。
\u{十六進数}(C++23) UCS-4文字を表す。\uよりも範囲がわかりやすい。
\N{ユニバーサル文字名}(C++23) 文字を名前で指定する。\N{HIRAGANA LETTER A}は文字「あ」を意味する。
\改行。つまり行末の\直後の改行を取り除きその行と次の行を連結する。マクロ定義で改行する場合には必須となる。
_アンダースコアはアルファベットなどと同じく識別子名に使用できる。またメンバ変数を「name_」などと名付けるコーディング規約など様々なスタイルが存在する。ただし「__」(アンダースコア2つ)が含まれるかまたは「_大文字」で始まる識別子はすべての場所で予約されている。「_」で始まる識別子はグローバル名前空間内で予約されている。使用しない変数や、型名だけで機能が自明なstd::lock_guard変数名などを単に「_」とする例もあるが衝突しやすい名前である。ローカライゼーション用にgettextライブラリと組み合わせて「_("msg")」,「N_("")」などが使用されることがある。
_t標準ライブラリで名前の最後に「_t」を付けたものは型名を表している(std::size_tなど)、またC++14以降の<type_traits>ヘッダのメタ関数名の末尾の「_t」はusingを使ったtype aliasで結果の型を表す(std::add_const_t<T> は typename std::add_const<T>::type と同じ)。
_vC++17の標準ライブラリでは上記「_t」と同じように「_v」を最後に付けて ::valueを省略可能。
_TWindowsSDKにおいて_Tはマルチバイト文字とワイド文字の切り替えマクロ。
_文字プレースホルダ。アンダースコアと一文字の識別子またはアンダースコア単独の識別子はstd.bind、boost.bind、boost.lambda、boost.phoenix、boost.mpl、boost.typeerasure、boost.spiritなどのライブラリで placeholder として用いられている。_1_a_など。boost.xpressiveではマッチする文字種の指定などにも。
リテラル_接尾辞ユーザー定義リテラル。接尾辞は一般に_から始まる。アンダースコア以外の文字から始まる接尾辞は予約されている。

auto speed = 10_mile / 30min;
auto graph = "{ a -> b -> c; a ->d; }"_digraph_dot;

operator "" 接尾辞(引数)ユーザー定義リテラルの定義

constexpr LengthSI operator "" _mile(unsigned long long int val) {
     return LengthSI(val * 1609.344);
}

operator 型名()型変換演算子。explicitを付けることを検討せよ。

struct s {
    explicit operator bool() const { return true; }
};
s object;
if (object) {}

operator 演算子(引数リスト)演算子の定義。演算子の呼び出し。

struct s {
bool operator == (s const& rhs) const { //演算子の定義
    return this->val == rhs.val; 
}
int val = 0;
};

s x,y;
x.operator == (y);// ==演算子の呼び出し
x == y; //同じく

operator ()(引数リスト)関数呼び出し演算子。これを定義したクラスは関数オブジェクトと呼ばれる。
operator ++()前置インクリメント。--の場合は前置ディクリメント。
operator ++(int)後置インクリメント。--の場合は後置ディクリメント。intの仮引数は前置と後置を区別するためのダミー引数。
スペース、タブ文字、改行等(ホワイトスペース)トークンの区切り。基本的にこれが無いと区切りが分からない場合以外はいくつあろうが関係ない。例外としては文字(列)リテラル内や、関数風マクロとオブジェクト風マクロの区別やマクロでの改行など。またキーワードや識別子など連続している必要のある単語内に挟むことは基本的にはできない。
アルファベットがすべて大文字の名前慣用的にマクロであることを示すことが多い。

#define PREVENT_REPLACE
int max PREVENT_REPLACE (void);
//お行儀の悪い小文字のmaxという関数風マクロが定義されて
//いる環境で同名の通常関数をマクロに干渉されないように宣言している。
//これはマクロが前から順に置き換えられるが関数風マクロは
//「 トークン(略) 」 の形でしか置き換えられないため。

and、and_eq、bitor、or_eq、or、xor_eq、xor、not、compl、not_eq、bitandいずれも&&、&=、|、|=、||、^=、^、!、~、!=、&の代替表現

if (not x) {  // if (!x) { に同じ
}

<%、%>、<:、:>、%:何れも{、}、[、]、#の代替表現。

%:include <iostream>
int main() <%
 return 0;
%>

??文字??に続く1文字はトライグラフ。例えば ??=は#と解釈される。C++17で廃止される。
$基本文字集合には含まれない。つまり普通は文字(列)リテラル以外では使用されない文字(識別子として使用される例は無いわけではない)
@基本文字集合には含まれない。VC拡張で#@の項目参照。Objective-Cに現れる。また規格文章や説明などで@=などとして+=や-=などの演算子をまとめて表記することに用いられる。
`基本文字集合には含まれない。
<?、>?、<?=、>?=古いgcc拡張で最小値または最大値を求める。=の付いているものは+=などと同じで求めた値を左辺に代入する。
[*]C++ではなくC99の機能で関数プロトタイプの配列引数が可変長であることを表明する。

void h(double multidim[*][*]);
void f(size_t, int[const *]); //C99だと[]の中に修飾子が書ける
void f(size_t n, int ar[const n]) { }
//中身は結局のところ以下と同じ
void h(double*);
void f(size_t, int* const);
void f(size_t n, int* const ar) {}

//gを呼び出すときは10要素以上の配列を確実に渡す必要がある
void g(int a[static 10]); 
//中身は結局のところ以下と同じ
void g(int* a); 

(型){ }C++ではなくC99の機能で複合リテラル(compound literal)を表す。無名のオブジェクトを生成するがその値はlvalueである。上記designated initializerと組み合わせることもできる。

//C99の compound literal
int* p = (int []){0,1,2}; //同じスコープならアドレスを後で利用可

戻り値型 関数名(仮引数リスト) return 名前; { }古いgcc拡張で関数の戻り値に名前を付ける。

int f() return r; {
 r = 0;
}

戻り値型 関数名(名前だけの仮引数リスト) 型名 名前; { }C++ではなくK&R時代のC言語で引数の型名を後に書く形式。型安全ではない。

void f(a) int a; { // int a;を省略することもできる
}
void g(); //これもC言語においては型安全ではない
// void g(void); のほうが良い

関数名(仮引数リスト)C++ではなくC89以前のC言語で関数宣言の戻り値型を省略したもの。暗黙的に戻り値型はintとなる。

f(char* p);

T U N R A1テンプレートパラメータの名前としてよく利用される。Nは長さ、Rは戻り値型、Aは引数型などに
(ベクトル型)(要素,要素)OpenCL C言語のベクトルリテラル

float4 a = (float4)(1,2,3,4);
float4 b = a.xyzw; //x y z wが個別の要素に対応
float2 c = a.s12; //sと16進数で要素を位置で指定する
float2 d = a.odd; //奇数位置の要素。その他 even,hi,lowなど

一部の演算子はマクロの #if や #elif でも大体同じ感覚で使用可能です。

各種ライブラリでは演算子オーバーロードして特殊な意味を持たせている場合があります。
boost.assignでは+=やカンマ演算子,や関数呼び出し演算子()オーバーロードして使用。
boost.signals2では+=をスロットの接続に。
boost.serializationでは&<<>>を入出力の演算子として使用。 boost.lambdaやboost.xpressiveやboost.spiritやboost.protoなどは大量の演算子オーバーロードして使用。boost.asioのyield_contextでは[]をエラーコードを格納するために使用。

説明の中で不定値としてあってもstaticもしくはグローバル変数の場合には最低限ゼロ初期化はされています。
C++17より組み込みの演算子の評価順序が定まっていればオーバーロードされた場合でも評価順序が同一となります。
標準のユーザー定義リテラルを使用するには事前に必要なヘッダのインクルードと using namespace std::literals; などとする必要があります。 [NS略 :]とか@とか^とかがよく出てくるのはObjective-C&C++


ビット演算子 ^ & | は比較演算子よりも優先順位が低いことに注意してください。
演算子の優先順位(cppreference) https://ja.cppreference.com/w/cpp/language/operator_precedence

Linuxでアプリを自動起動

Linuxでアプリを自動起動Windowsのスタートアップ相当)するならinit.d等ではなくデスクトップ環境や各ウィンドウマネージャの設定を使うのが簡単で良いようです。

たとえばLXDEskype自動起動するなら/etc/xdg/lxsession/LXDE/autostartに(Lubuntuならおそらく/etc/xdg/lxsession/Lubuntu/autostart)に@skypeという行を追加すれば良いだけです。ただしエディタは管理者権限が必要。また~/.config/autostartフォルダに.desktopファイルを作る方法もあるようです。http://wiki.lxde.org/en/Autostart

IceWMなら~/.icewm/にstartupという名前のスクリプトファイルを作り

#!/bin/bash
skype&

と入力して保存し、

chmod +x startup

で実行属性を付ける。

KDE(OpenSUSEなど)なら~/.config/autostart/に上と同じくスクリプトファイルを置けばよいようです。
Cinnamon(Mintなど)ならGUIツールが用意されていて「メニュー」->「設定」->「自動起動するアプリケーション」から設定できるようです。

いずれにしろ自分の使用しているデスクトップ環境名とautostartなどのキーワードで検索すれば方法は見つかると思います。

ALSAの作法とか

自分で試してみた限りのことを書きます。

snd_pcm_openの引数に"hw:0,0"を渡す例が多くみられるがこれはデバイスを独占してしまうためお行儀がよろしくないと思われる。そこで出力先は"default"やミキサーの"plug:dmix"にするとよい。これでほかのプロセスからも音声を出力できる。"default"はPulseAudioにフォールバックしているようなので一番好ましいかもしれない。
そしてさらに出力先をコントロールしたい場合は"/home/USERNAME/.asoundrc"や "/etc/asound.conf"などの設定ファイルで予め適当な出力先を作っておき、snd_pcm_openに"plug:***"の形で指定するのが良い。

またhw:0,0の場合periodを指定しないと音がプツプツになる。snd_pcm_hw_params_set_periodsを使用して設定できるが値は8,16,32以外は音がおかしくなった。plug:dmixならperiodを指定せずとも滑らかに再生された。

snd_pcm_hw_params_set_channelsでモノラルのデータを使用しようと1を指定すると失敗した。(snd_pcm_openにhwを指定した時なのでplug:dmixではどうなのかわからないが)ステレオを指定するのが無難だと思う。.asoundrcなどの側でパラメータをいじれるので適当な出力先を作るのが良いと思われる。

snd_pcm_availを使用してバッファの空きを確認できる。
snd_pcm_writeiでデータを書き込む。snd_pcm_writeiはデフォルトでデータの再生完了を待たずに制御を返す。snd_pcm_avail, snd_pcm_writeiは両方ともアンダーラン発生時に-EPIPEエラーを返すのでsnd_pcm_recoverを呼んで復帰させる必要がある。これがないとかなり信頼性に欠ける。
データの再生完了まで待つにはsnd_pcm_drainを呼び出す。ちなみにsnd_pcm_drainはsnd_pcm_openにSND_PCM_NONBLOCKを指定すると待機せずに-EAGAINを返して素通りする。SND_PCM_NONBLOCKを使用するメリットは感じられなかった。

まあLinuxなのでsystem関数からaplayに丸投げするのが簡単なのかもしれない。

ここまでALSAAPIについて書いてきてあれだが、PulseAudioを使った方が遥かに柔軟で簡単で適切だ。Simple APIとやらも用意されていて同期再生するだけならこれで十分。

#include <pulse/simple.h>
#include <iostream>

int play(const void* buffer, int size)
{
    pa_sample_spec pas{};
    pas.format = PA_SAMPLE_S16NE;
    pas.channels = 2;
    pas.rate = 44100;

    int err;
    pa_simple* handle = pa_simple_new(NULL, "test", PA_STREAM_PLAYBACK, NULL, "tes", &pas, NULL, NULL, &err);
    if (!handle) {
        cout << "open error" << endl;
    }

    int n;
    if ((n = pa_simple_write(handle, buffer, size, &err)) < 0) {
        cout << "write error" << endl;
    }

    pa_simple_drain(handle, &err);
    pa_simple_free(handle);
}

Boost.TypeErasureのドキュメント翻訳

訳してみました。型や関数ごとの説明以外は訳してあります。
本家

Boost.TypeErasure

Steven Watanabe

Copyright © 2011-2013 Steven Watanabe

Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

紹介
Boost.TypeErasureライブラリはC++においてコア言語が提供するものよりもより柔軟な実行時多態性を提供する。
C++は仮想関数とテンプレートという二つの異なる種類の多態性を持ち、ぞれぞれ利点と不利な点を持つ。
・仮想関数は実行時まで解決されないが、テンプレートは常にコンパイル時に解決される。もしあなたの型が実行時に変化しうるなら(例えばユーザーの入力にその型が依存するならば)テンプレートによる静的多態性はあまり役立たない。
・仮想関数は分割コンパイルに用いることができる。テンプレートの本体はそれが使用される全ての翻訳単位ごとに利用できる必要があるため、コンパイルを遅くしリビルド時間を増加させる。
・仮想関数は自動的に明示的な引数の要件を作成する。テンプレートはそれらがインスタンス化される際にチェックされるのみであり、テストやアサートやドキュメントにおいて余分な労力を要求する。
コンパイラは関数テンプレートがインスタンス化される度に新しくそのコピーを作成する。これはコンパイラが静的に何もかも知っているため良い最適化を可能にする一方でバイナリサイズの肥大化も引き起こす。
・テンプレートは値セマンティクスをサポートする。"intのように振舞い"そして共有されないオブジェクトは理解が容易である。その一方で仮想関数を使用するには(スマート)ポインタや参照を使用する必要がある。
・テンプレートライブラリはサードパーティの型を非侵入的に適用でき、シームレスな相互運用性を確保できる。仮想関数の場合基底クラスを継承したラッパーを作る必要がある。
・テンプレートは複数の型に関係する制約を扱うことができる。例えばstd::for_eachはイテレータレンジとそのレンジの要素ごとに呼ばれる関数を取る。仮想関数はそのような制約を真に表現できない。
Boost.TypeErasureライブラリはテンプレートの優れた抽象化能力と仮想関数の実行時の柔軟性を組み合わせる。
Boostはこの種の多態性の幾つかの特殊解を持っている。
・boost::any は CopyConstructible な型用である。
・boost::function は関数のように呼び出すことができるオブジェクト用である。
・Boost.Range は any_iterator を提供する。
Boost.TypeErasure は任意の要求をサポートするようにこれらを一般化し、事前定義された一般的なコンセプト群を提供する。

このドキュメントの読み方
過度な冗長性を避けるため全てのコード例は幾つかのusing directiveが定義されていると仮定する。

namespace mpl = boost::mpl;
using namespace boost::type_erasure;

基本的な使用法

(この節のコード例のソースはbasic.cppを参照のこと)
このライブラリの中心を成すクラスは any である。anyは指定した要件に適合するオブジェクトを格納できる。これらの要件はanyにMPLシーケンスとして渡される。

MPLシーケンスは複数のコンセプトを組み合わせる。ひとつのコンセプトのみを望む稀なケースではそれをMPLシーケンスでラップする必要は無い。

any<mpl::vector<copy_constructible<>, typeid_<>, relaxed> > x(10);
int i = any_cast<int>(x); // i == 10

copy_constructibleはオブジェクトのコピーと破棄を許可する組み込みのコンセプトである。typeid_は実行時型情報を提供するのでany_castを使用することができる。relaxedは便利で多様な既定動作を有効にする。relaxedを指定しない場合、anyは指定されたコンセプトのみを正確にサポートし、それ以外はサポートしない。特にrelaxedはanyのデフォルトコンストラクトと代入を許可する。
さて、この例ではたいした事をしておらずxはほとんどboost::anyと同じである。これをoperator++やoperator<<のような幾つかの演算子を追加することによってより面白くできる。

any<
    mpl::vector<
        copy_constructible<>,
        typeid_<>,
        incrementable<>,
        ostreamable<>
    >
> x(10);
++x;
std::cout << x << std::endl; // prints 11

本ライブラリは大半のC++演算子のコンセプトを提供しているが、これは明らかに全ての利用例をカバーするものではない。しばしば自身の要件に応じて定義する必要がある。そこで幾つかのSTLコンテナに定義されているpush_backメンバを例に取ってみよう。

BOOST_TYPE_ERASURE_MEMBER((has_push_back), push_back, 1)

void append_many(any<has_push_back<void(int)>, _self&> container) {
    for(int i = 0; i < 10; ++i)
        container.push_back(i);
}

has_push_backという名前のコンセプトを定義するためにBOOST_TYPE_ERASURE_MEMBERマクロを使用している。2番目のパラメーターはメンバ関数の名前で最後のマクロパラメーターは引数の数を示していてpush_backが単項であるから1である。has_push_backを使用する時は関数のシグネチャvoid(int)を示す必要がある。これはanyに格納する型が以下のようなメンバを持つ必要性があることを意味する。

void push_back(int);

このように我々はappend_manyをstd::vector<int>,std::list<int>またはstd::vector<long>(なぜならintはlongに変換可能だから)で呼び出すことができる。しかしstd::list<std::string>またはstd::set<int>ではできない。

またappend_manyは自身の引数自体を演算するしかないことに注意せよ。コピーを作ることはできない。これを扱うにはanyの第2引数に_self&を使用する。_selfはplaceholderである。_self&を使用することによって自身のオブジェクトを割り当てる代わりに外部オブジェクトへの参照をanyに格納することを示す。

ここでは別のplaceholderも実際には存在している。has_push_backの第2パラメータは既定で_selfが指定されている。もしconstメンバ関数を定義したいならそれを以下に示すようにconst _selfに変更する必要がある。

BOOST_TYPE_ERASURE_MEMBER((has_empty), empty, 0)
bool is_empty(any<has_empty<bool(), const _self>, const _self&> x) {
    return x.empty();
}

フリー関数を指定するにはBOOST_TYPE_ERASURE_FREEマクロを使用できる。

BOOST_TYPE_ERASURE_FREE((has_getline), getline, 2)
std::vector<std::string> read_lines(any<has_getline<bool(_self&, std::string&)>, _self&> stream)
{
    std::vector<std::string> result;
    std::string tmp;
    while(getline(stream, tmp))
        result.push_back(tmp);
    return result;
}

has_getlineの使用方法は前述のhas_push_backに非常に近い。違いはplaceholderの_selfが関数シグネチャ内に個別の引数の代わりに渡されていることである。

placeholderは第1引数にある必要はない。第2引数にすることも容易である。

void read_line(any<has_getline<bool(std::istream&, _self&)>, _self&> str)
{
    getline(std::cin, str);
}

コンセプトの結合
(この節のコード例のソースはcompose.cppを参照のこと)

複数のコンセプトをMPLシーケンスを使用して結合できる。

template<class T = _self>
struct arithmetic :
    mpl::vector<
        copy_constructible<T>,
        addable<T>,
        subtractable<T>,
        multipliable<T>,
        dividable<T>,
        equality_comparable<T>,
        less_than_comparable<T>
    >
{};

これでarithmeticはこのベースコンセプトのいずれとしても使用できるコンセプトになる。

複数の引数を持つ関数
(この節のコード例のソースはmulti.cppを参照のこと)
演算はひとつ以上のany引数を持つことができる。例として二項の加算を使用してみよう。

typedef any<
    mpl::vector<
        copy_constructible<>,
        typeid_<>,
        addable<>,
        ostreamable<>
    >
> any_type;
any_type x(10);
any_type y(7);
any_type z(x + y);
std::cout << z << std::endl; // prints 17

これはマルチメソッドではない。この+の引数の基礎の型は同じでなければならない、さもなくば未定義動作になる。この例は正しい。なぜならば引数は両方ともintを保持しているからである。

relaxedを指定することにより引数の型が間違っていても未定義動作にならず例外を投げるようになる。

addable<>は引数の型が正確に同じであることを要求する。しかしこれは全ての加算の使用法をカバーしていない。例えば、ポインタ演算はポインタと整数を引数に取りポインタを返す。この種の幾つかの型の間の関係をplaceholderに関連付けた型ごとに識別することでキャプチャすることができる。ポインタをplaceholder _aで表現し、整数をplaceholder _bで表現することにしよう。

int array[5];

typedef mpl::vector<
    copy_constructible<_a>,
    copy_constructible<_b>,
    typeid_<_a>,
    addable<_a, _b, _a>
> requirements;

この新しいコンセプトではaddable<_a, _b, _a>は _a + _b -> _a というポインタの加算ルールを取り扱っている。
また、独立して変数をキャプチャすることはもうできない。

any<requirements, _a> ptr(&array[0]); // illegal

これは動かない。なぜならばライブラリはコンセプトバインディングをキャプチャするときに_bをどの型にバインドしたらいいか知る必要があるからだ。anyをコンストラクトするときに両方のplaceholderのバインディングを指定する必要がある。

typedef mpl::map<mpl::pair<_a, int*>, mpl::pair<_b, int> > types;
any<requirements, _a> ptr(&array[0], make_binding<types>());
any<requirements, _b> idx(2, make_binding<types>());
any<requirements, _a> x(ptr + idx);
// x now holds array + 2

ここで+の引数は同じ型ではなく、引数_aはint*にマップし引数_bはintにマップすることを要求している。
またtupleを使うことで明示的にマップを書くことを回避できる。tupleはその全ての引数からplaceholderのバインディングを組み合わせる便利なクラスである。

tuple<requirements, _a, _b> t(&array[0], 2);
any<requirements, _a> y(get<0>(t) + get<1>(t));

コンセプト詳細

カスタムコンセプトの定義
(この節のコード例のソースはcustum.cppを参照のこと)

先ほどBOOST_TYPE_ERASURE_MEMBERをpush_backをサポートするコンテナ用のコンセプトを定義するために使用した。しかしながら時々このインターフェイスは柔軟性が十分とは言えなくなる。本ライブラリは動作を完全に制御するための低レベルインターフェイスを提供する。ではhas_push_backを定義するために何が必要になるか見ていこう。最初にhas_push_backテンプレート自身を定義する必要がある。これには二つのテンプレートパラメータが必要になる。ひとつはコンテナ用でもうひとつは要素の型用である。このテンプレートは演算を実行するのに使用されるapplyという名前のstaticメンバ関数を持たなければならない。

template<class C, class T>
struct has_push_back
{
    static void apply(C& cont, const T& arg) { cont.push_back(arg); }
};

これで演算をディスパッチするためにcallを用いてanyで使用できる。

std::vector<int> vec;
any<has_push_back<_self, int>, _self&> c(vec);
int i = 10;
call(has_push_back<_self, int>(), c, i);
// vec is [10].

二番目にやることはc.push_back(10)と呼べるようにanyをカスタマイズすることだ。これはconcept_interfaceを特殊化することで行う。第1引数はhas_push_backでhas_push_backコンセプトを使用する全てのanyにメンバ関数を注入するためである。第2引数はBaseでライブラリによって複数のconcept_interfaceを一緒にチェインさせるのに使用される。我々はこれをpublic継承する必要がある。またBaseは完全なany型へのアクセスを手に入れるために使用される。第3引数はこのanyを表現するplaceholderである。もし誰かがpush_back<_c, _b>を使用したならば、我々はコンテナにpush_backメンバのみ挿入することを望む。値型ではなく。よって第3引数はコンテナのplaceholderである。

push_backを定義するとき引数の型はas_paramメタ関数を使用する。これはTがplaceholderの場合を扱っているだけである。もしTがplaceholderでないならばメタ関数はそれ自身の引数 const T&をそのまま返すだけある。

namespace boost {
namespace type_erasure {
template<class C, class T, class Base>
struct concept_interface<has_push_back<C, T>, Base, C> : Base
{
    void push_back(typename as_param<Base, const T&>::type arg)
    { call(has_push_back<C, T>(), *this, arg); }
};
}
}

そこで我々の例はこうなる。

std::vector<int> vec;
any<has_push_back<_self, int>, _self&> c(vec);
c.push_back(10);

これが我々が望んだものである。

オーバーロード
(この節のコード例のソースはoverload.cppを参照のこと)

concept_interfaceはanyに任意の宣言の注入を可能にする。これはとても柔軟性があるが幾つかの注意すべき落とし穴がある。時々同じコンセプトを違ったパラメータで何回か使用したいときがある。concept_interfaceを特殊化してオーバーロードを正しく扱うことは少々トリッキーだ。fooというコンセプトがあったとして以下のように動かしたい。

any<
    mpl::vector<
        foo<_self, int>,
        foo<_self, double>,
        copy_constructible<>
    >
> x = ...;
x.foo(1);   // calls foo(int)
x.foo(1.0); // calls foo(double)

concept_interfaceは直線的に継承チェーンを作りそれ以上のことをしない。そのためひとつのfooのオーバーロードが他のものを隠してしまう。
ここに私が見つけたきちんと動くテクニックがある。
メンバ関数用には二つの特殊化の使用を回避する方法が見つけられなかった。

template<class T, class U>
struct foo
{
    static void apply(T& t, const U& u) { t.foo(u); }
};

namespace boost {
namespace type_erasure {

template<class T, class U, class Base, class Enable>
struct concept_interface< ::foo<T, U>, Base, T, Enable> : Base
{
    typedef void _fun_defined;
    void foo(typename as_param<Base, const U&>::type arg)
    {
        call(::foo<T, U>(), *this, arg);
    }
};

template<class T, class U, class Base>
struct concept_interface< ::foo<T, U>, Base, T, typename Base::_fun_defined> : Base
{
    using Base::foo;
    void foo(typename as_param<Base, const U&>::type arg)
    {
        call(::foo<T, U>(), *this, arg);
    }
};

}
}

これはSFINAEをusing declarationが必要かどうか判別するために使用している。concept_interfaceの第4引数はSFINAEの使用に伴う常にvoidのダミーパラメータである。私が過去に試した問題のほかの解決策としてはfunのダミー宣言を注入し常にusing declaration内に入れることだ。これはいくつかの理由から劣っている解決策である。これはダミーオーバーロードを追加するための余分なインターフェイスを要求する。またこれはユーザーが一つだけのオーバーロードしか求めていない場合でもfunが常にオーバーロードされることを意味する。これはfunのアドレスを取ることを困難にする。

SFINAEの使用は幾つかのコードの重複を要求することに注意せよ。concept_interfaceの実装は普通1行で書けるので重複するコードの総量は相対的に小さい。少々煩わしいが、私はこれはベターな解決策のためには受け入れ可能なコストだと信じている。

フリー関数用にはinline friendが使用できる

template<class T, class U>
struct bar_concept
{
    static void apply(T& t, const U& u) { bar(t, u); }
};

namespace boost {
namespace type_erasure {

template<class T, class U, class Base>
struct concept_interface< ::bar_concept<T, U>, Base, T> : Base
{
    friend void bar(typename derived<Base>::type& t, typename as_param<Base, const U&>::type u)
    {
        call(::bar_concept<T, U>(), t, u);
    }
};

template<class T, class U, class Base>
struct concept_interface< ::bar_concept<T, U>, Base, U, typename boost::disable_if<is_placeholder<T> >::type> : Base
{
    using Base::bar;
    friend void bar(T& t, const typename derived<Base>::type& u)
    {
        call(::bar_concept<T, U>(), t, u);
    }
};

}
}

基本的にオーバーロードが確実にplaceholderである第1引数に注入されるように各引数ごとにconcept_interfaceを特殊化する必要がある。お気づきかもしれないが引数の型は少々トリッキーである。最初の特殊化では第1引数はas_paramの代わりにderivedを使用している。この理由はもしas_paramを使用した場合同じ関数を2回定義することにより最後にはODR違反になるからである。同様に二番目の特殊化にSFINAEを使用して引数が両方ともplaceholderの場合にbarが確実に一度だけ定義されるようにしている。メタプログラミングを少し用いればこの二つの特殊化された関数を統一することは可能だろうが、引数が大量でもない限りおそらくやるだけの価値はないだろう。

コンセプトマップ
(この節のコード例のソースはconcept_map.cppを参照のこと)

時々コンセプトモデルに型を非侵入的に適用できると便利なことがある。例えばstd::type_infoをless_than_comparableモデルにしたい状況を考えてみよう。これを行うには単にコンセプト定義を特殊化すればよい。

namespace boost {
namespace type_erasure {

template<>
struct less_than_comparable<std::type_info>
{
    static bool apply(const std::type_info& lhs, const std::type_info& rhs)
    { return lhs.before(rhs) != 0; }
};

}
}

大半は可能だが、しかし全ての組み込みのコンセプトが特殊化できるとは限らない。コンストラクタ、デストラクタ、RTTIはライブラリから特別な扱いを受ける必要があり特殊化できない。プリミティブなコンセプトのみが特殊化できる。そんなわけでiteratorコンセプトも不可能である。

関連型
(この節のコード例のソースはassociated.cppを参照のこと)

typename T::value_type や typename std::iterator_traits<T>::reference といった関連型はテンプレートプログラミングにおいて極めて一般的である。Boost.TypeErasureはdeducedテンプレートを使用してこれらを取り扱う。deducedはメタ関数によって呼ばれることによりバインドされる型が決まり明示的に指定する必要がないことを除いて普通のplaceholderと同じである。

たとえばイテレータ、生ポインタ、もしくはスマートポインタを保有可能なコンセプトを以下のように定義できる。まずその関連型を定義するpointeeという名前のメタ関数を定義する。

template<class T>
struct pointee
{
    typedef typename mpl::eval_if<is_placeholder<T>,
        mpl::identity<void>,
        boost::pointee<T>
    >::type type;
};

単純にboost::pointeeを使うことができないことに注意せよ。なぜならこのメタ関数はplaceholderでインスタンス化しても安全にする必要があるからだ。エラーを起こさない限りそれが何を返そうが構わない。(本ライブラリはplaceholderを用いてインスタンス化をすることは決してないが、ADLが偽のインスタンス化を起こす可能性がある。)

template<class T = _self>
struct pointer :
    mpl::vector<
        copy_constructible<T>,
        dereferenceable<deduced<pointee<T> >&, T>
    >
{
    // provide a typedef for convenience
    typedef deduced<pointee<T> > element_type;
};

ここでxのコンセプトは_selfとpointer<>::element_typeの二つのplaceholderを使用している。xをint*でコンストラクトするときpointer<>::element_typeはpointee<int*>::typeに推論され、それはintである。よってxをdereferencingするとintを保持するanyを返す。

int i = 10;
any<
    mpl::vector<
        pointer<>,
        typeid_<pointer<>::element_type>
    >
> x(&i);
int j = any_cast<int>(*x); // j == i

時々関連型が指定された型であることを要求したいことがある。これはsame_typeコンセプトを使用することによって解決できる。ここでintの要素型を指すどんなポインタをも保有することができるanyを作成する。

int i = 10;
any<
    mpl::vector<
        pointer<>,
        same_type<pointer<>::element_type, int>
    >
> x(&i);
std::cout << *x << std::endl; // prints 10

このようにsame_typeを使用することにより事実上ライブラリが全てのpointer<>::element_typeの使用をintで置き換えることになり、常にそれがintにバインドされているということを保障できる。よってxをdereferencingするとintが返る。
またsame_typeはplaceholderが二つでも使用できる。これは関連型を何度も書く代わりに簡単な名前の使用を可能にする。

int i = 10;
any<
    mpl::vector<
        pointer<>,
        same_type<pointer<>::element_type, _a>,
        typeid_<_a>,
        copy_constructible<_a>,
        addable<_a>,
        ostreamable<std::ostream, _a>
    >
> x(&i);
std::cout << (*x + *x) << std::endl; // prints 20

Anyの使用
コンストラク
(この節のコード例のソースはconstruction.cppを参照のこと)
本ライブラリはanyがコンストラクタをキャプチャ可能にするconstructibleコンセプトを提供する。単独のテンプレート引数は関数シグネチャ形式でなければならない。戻り値型は構築される型を指定するplaceholderである。引数型はコンストラクタの引数である。

typedef mpl::vector<
    copy_constructible<_a>,
    copy_constructible<_b>,
    copy_constructible<_c>,
    constructible<_a(const _b&, const _c&)>
> construct;

typedef mpl::map<
    mpl::pair<_a, std::vector<double> >,
    mpl::pair<_b, std::size_t>,
    mpl::pair<_c, double>
> types;

any<construct, _b> size(std::size_t(10), make_binding<types>());
any<construct, _c> val(2.5, make_binding<types>());
any<construct, _a> v(size, val);
// v holds std::vector<double>(10, 2.5);

ここでデフォルトコンストラクタを望む場合は?我々は保持される型のデフォルトコンストラクタを呼び出すanyのデフォルトコンストラクタを持つことができない。なぜなら保持される型がなんであるか知る方法がないからだ。つまりplaceholderのバインド情報を明示的に渡す必要性がある。

typedef mpl::vector<
    copy_constructible<>,
    constructible<_self()>
> construct;

any<construct> x(std::string("Test"));
any<construct> y(binding_of(x)); // y == ""

これはデフォルトコンストラクタに限定された方法ではない。もしコンストラクタが引数を取るのならばそれらはバインディングの後に渡すことができる。

typedef mpl::vector<
    copy_constructible<>,
    constructible<_self(std::size_t, char)>
> construct;

any<construct> x(std::string("Test"));
any<construct> y(binding_of(x), 5, 'A');

変換
(この節のコード例のソースはconvert.cppを参照のこと)
変換が"アップキャスト"である限りanyは他のanyへ変換することができる。

typedef any<
    mpl::vector<
        copy_constructible<>,
        typeid_<>,
        ostreamable<>
    >
> any_printable;
typedef any<
    mpl::vector<
        copy_constructible<>,
        typeid_<>
    >
> common_any;
any_printable x(10);
common_any y(x);

この変換は可能である。なぜならばcommon_anyの要件はany_printable要件のサブセットだからである。逆方向の変換は不可。

common_any x(10);
any_printable y(x); // error

参照
(この節のコード例のソースはreferences.cppを参照のこと)
参照でキャプチャするには単にplaceholderに参照を追加すればよい。

int i;
any<typeid_<>, _self&> x(i);
any_cast<int&>(x) = 5; // now i is 5

_selfは既定のplaceholderである。なので_self&を使うことは簡単である。また代わりに別のplaceholderを使用しても良い。any<typeid_<_a>, _a&>も全く同じ挙動をする。

参照は再バインドすることはできない。本来のC++参照と同じく、一度初期化してしまえば他のものを指すように変更することはできない。

int i, j;
any<typeid_<>, _self&> x(i), y(j);
x = y; // error

メモ

他の演算と同じく、参照のx=yはiとjに対して作用する。もしassignable<>がコンセプトに含まれていればこのような代入は可能であるが、xは依然としてiへの参照を保持する。

参照は他のanyへバインドできる。

typedef mpl::vector<
    copy_constructible<>,
    incrementable<>
> requirements;

any<requirements> x(10);
any<requirements, _self&> y(x);
++y; // x is now 11

もし参照が参照元オブジェクトの寿命が切れるか初期化された後に使用されると未定義動作である。

typedef mpl::vector<
    copy_constructible<>,
    incrementable<>,
    relaxed
> requirements;
any<requirements> x(10);
any<requirements, _self&> y(x);
x = 1.0;
++y; // undefined behavior.

これは参照が値から構築される場合にのみ適用される。もし参照が他の参照から構築される場合、新しい参照は古い参照に依存しない。

any<requirements> x(10);
boost::shared_ptr<any<requirements, _self&> > p(
    new any<requirements, _self&>(x));
any<requirements, _self&> y(*p); // equivalent to y(x);
p.reset();
++y; // okay

constと非const参照の両方がサポートされている。

int i = 0;
any<incrementable<>, _self&> x(i);
any<incrementable<>, const _self&> y(x);

非const参照はconst参照へ変換できるが逆方向はできない。当然ながらconst参照には変更を加えるような演算は適用できない。

any<incrementable<>, _self&> z(y); // error
++y; // error

文法の限界
たいていの場合anyは基礎オブジェクトを使用するのと同じ文法を持っている。しかしながらこれを実装することができない幾つかの場合が存在する。any参照はプロキシであり本当の参照が要求される場所で使用することはできない。特に、forward_iteratorは(value_typeを固定せずに) ForwardIteratorを満たすように作成することはできない。他の違いとしては少なくともひとつ以上のany引数を取らない全ての演算は明示的に型情報を渡す必要性がある。静的メンバ関数とコンストラクタはこのカテゴリに属すことがある。これが意味することはジェネリックアルゴリズムがany引数に適用された場合に動かないかもしれないということだ。


多相レンジフォーマッター
(この節のコード例のソースはprint_sequence.cppを参照のこと)
この例では幾つかの異なった方法でシーケンスをフォーマット可能にするクラス階層を定義している。どんなシーケンスやストリーム型でも扱うことができるようにしたい。レンジフォーマットすることは個別の要素をフォーマットすることとは独立しているからである。そこでこのようなインターフェイスが必要になる。

class abstract_printer {
public:
    template<class CharT, class Traits, class Range>
    virtual void print(std::basic_ostream<CharT, Traits>& os, const Range& r) const = 0;
};

残念なことにこれは不可能だ。仮想関数はテンプレートにはなれないからだ。しかしながらBoost.TypeErasureを使用することによってこれと同じことをするクラスを定義することが可能になる。

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/iterator.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/tuple.hpp>
#include <boost/type_erasure/same_type.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator.hpp>
#include <iostream>
#include <iomanip>
#include <vector>

using namespace boost::type_erasure;

struct _t : placeholder {};
struct _iter : placeholder {};
struct _os : placeholder {};

template<class T, class U = _self>
struct base_and_derived
{
    static T& apply(U& arg) { return arg; }
};

namespace boost {
namespace type_erasure {

template<class T, class U, class Base>
struct concept_interface<base_and_derived<T, U>, Base, U> : Base
{
    operator typename rebind_any<Base, const T&>::type() const
    {
        return call(base_and_derived<T, U>(), const_cast<concept_interface&>(*this));
    }
    operator typename rebind_any<Base, T&>::type()
    {
        return call(base_and_derived<T, U>(), *this);
    }
};

}
}

// abstract_printer - フォーマットするシーケンス用の抽象基底クラス
class abstract_printer {
public:
    // print - シーケンスを任意の方法で派生クラスのstd::ostreamに書き出す
    //
    // 要件: RengeはForward Rangeでその要素がosにプリントできる必要がある。
    template<class CharT, class Traits, class Range>
    void print(std::basic_ostream<CharT, Traits>& os, const Range& r) const {
        // 引数をキャプチャする
        typename boost::range_iterator<const Range>::type
            first(boost::begin(r)),
            last(boost::end(r));
        tuple<requirements, _os&, _iter, _iter> args(os, first, last);
        // そして実際の実装へ転送する
        do_print(get<0>(args), get<1>(args), get<2>(args));
    }
    virtual ~abstract_printer() {}
protected:
    // print引数のコンセプト要件を定義し
    // any型をtypedefする
    typedef boost::mpl::vector<
        base_and_derived<std::ios_base, _os>,
        ostreamable<_os, _t>,
        ostreamable<_os, const char*>,
        forward_iterator<_iter, const _t&>,
        same_type<_t, forward_iterator<_iter, const _t&>::value_type>
    > requirements;
    typedef boost::type_erasure::any<requirements, _os&> ostream_type;
    typedef boost::type_erasure::any<requirements, _iter> iterator_type;
    // do_print - このメソッドは派生クラスで定義されなければならない。
    virtual void do_print(
        ostream_type os, iterator_type first, iterator_type last) const = 0;
};

// separator_printer - シーケンスの要素を固定文字列で区切って書き出す
//   例えばもしseparatorが", "ならばseparator_printerはカンマ区切りリストを出力する
class separator_printer : public abstract_printer {
public:
    explicit separator_printer(const std::string& sep) : separator(sep) {}
protected:
    virtual void do_print(
        ostream_type os, iterator_type first, iterator_type last) const {
        if(first != last) {
            os << *first;
            ++first;
            for(; first != last; ++first) {
                os << separator.c_str() << *first;
            }
        }
    }
private:
    std::string separator;
};

// column_separator_printer - separator_printerに似ていて、n要素ごとに改行を挿入する
class column_separator_printer : public abstract_printer {
public:
    column_separator_printer(const std::string& sep, std::size_t num_columns)
      : separator(sep),
        cols(num_columns)
    {}
protected:
    virtual void do_print(
        ostream_type os, iterator_type first, iterator_type last) const {
        std::size_t count = 0;
        for(; first != last; ++first) {
            os << *first;
            boost::type_erasure::any<requirements, _iter> temp = first;
            ++temp;
            if(temp != last) {
                os << separator.c_str();
            }
            if(++count % cols == 0) {
                os << "\n";
            }
        }
    }
private:
    std::string separator;
    std::size_t cols;
};

// aligned_column_printer - シーケンスの列を縦方向に整形する
//   たとえば { 1, 2, 3, 4, 5 } というシーケンスが与えられると
//   aligned_column_printer はこのようにプリントする
//   1   4
//   2   5
//   3
class aligned_column_printer : public abstract_printer {
public:
    aligned_column_printer(std::size_t column_width, std::size_t num_columns)
      : width(column_width),
        cols(num_columns)
    {}
protected:
    virtual void do_print(
        ostream_type os, iterator_type first, iterator_type last) const
    {
        if(first == last) return;
        std::vector<iterator_type> column_iterators;

        // 最大列数を見つける
        std::size_t count = 0;
        for(iterator_type iter = first; iter != last; ++iter) {
            ++count;
        }
        std::size_t rows = (count + cols - 1) / cols;
        count = 0;
        for(iterator_type iter = first; iter != last; ++iter) {
            if(count % rows == 0) {
                column_iterators.push_back(iter);
            }
            ++count;
        }

        iterator_type last_col = column_iterators.back();

        // 完全な行をプリントする
        while(column_iterators.back() != last) {
            for(std::vector<iterator_type>::iterator
                iter = column_iterators.begin(),
                end = column_iterators.end(); iter != end; ++iter)
            {
                static_cast<std::ios_base&>(os).width(width);
                os << **iter;
                ++*iter;
            }
            os << "\n";
        }

        // 最後の列がない行をプリントする
        column_iterators.pop_back();
        if(!column_iterators.empty()) {
            while(column_iterators.back() != last_col) {
                for(std::vector<iterator_type>::iterator
                    iter = column_iterators.begin(),
                    end = column_iterators.end(); iter != end; ++iter)
                {
                    static_cast<std::ios_base&>(os).width(width);
                    os << **iter;
                    ++*iter;
                }
                os << "\n";
            }
        }
    }
private:
    std::size_t width;
    std::size_t cols;
};

int main() {
    int test[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    separator_printer p1(",");
    p1.print(std::cout, test);
    std::cout << std::endl;
    column_separator_printer p2(",", 4);
    p2.print(std::cout, test);
    std::cout << std::endl;
    aligned_column_printer p3(16, 4);
    p3.print(std::cout, test);
}

型安全なprintf
(この節のコード例のソースはprintf.cppを参照のこと)

この例では型安全なprintfを実装するために本ライブラリを使用している。

この例はC++11の機能を使用している。動かすためには比較的新しいコンパイラを使用する必要がある。

#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/any.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/io/ios_state.hpp>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <string>

namespace mpl = boost::mpl;
using namespace boost::type_erasure;
using namespace boost::io;

// 引数を参照でキャプチャし、各々がストリーム出力操作を提供しなければならない他は何も要求しない。
typedef any<
    mpl::vector<
        typeid_<>,
        ostreamable<>
    >,
    const _self&
> any_printable;
typedef std::vector<any_printable> print_storage;

// 実装関数の先行宣言
void print_impl(std::ostream& os, const char * format, const print_storage& args);

// print
//
// 古典的なCのprintf関数のようにストリームに値を書き出す。
// 引数は以下のパターンにマッチするフォーマット文字列内の修飾子に基づいてフォーマットされる
//
// '%' [ argument-number '$' ] flags * [ width ] [ '.' precision ] [ type-code ] format-specifier
//
// このフォーマット文字列内のほかの文字はそのままストリームに書き出される。
// このシーケンスに加えて、"%%" は'%'文字を出力するために使用できる。
// 各要素の詳細は以下のとおりである。
//
// argument-number:
//   値は 1 から sizeof... T の間でなければならない。これはフォーマットする引数の
//   インデックスを表す。インデックスが指定されていない場合に引数は
//   順番に処理される。もしインデックスが一つの引数に指定された場合は
//   他のすべての引数についても指定しなければならない。
//
// flags:
//   以下の文字の零個以上の組み合わせから構成される。
//   '-': Left justify the argument
//   '+': Print a plus sign for positive integers
//   '0': Use leading 0's to pad instead of filling with spaces.
//   ' ': If the value doesn't begin with a sign, prepend a space
//   '#': Print 0x or 0 for hexadecimal and octal numbers.
//
// width:
//   プリントする最小幅を表す。これは整数または一つの'*'のどちらでもよい。
//   アスタリスクは次の引数(これはint型でなければならない)をwidthとして
//   読み取ることを意味する。
//
// precision:
//   数値の引数においてはプリントする桁数を指定する。
//   文字列(%s)において precision はプリントする最大文字数を指定する。
//   長い文字列は切りつめられるだろう。widthと同様にこれは整数もしくは
//   一つの'*'を指定できる。アスタリスクは次の引数(これはint型でなければ
//   ならない)をwidth [訳注:precisionの間違いと思われる]として読み取るこ
// とを意味する。もしwidthとprecisionの両方が'*'として指定された場合、
//   widthが先に読み込まれる。
//
// type-code:
//   これは無視されるがC printfとの互換性のために提供されている。
//
// format-specifier:
//   以下の文字の内何れか一文字でなければならない:
//   d, i, u: The argument is formatted as a decimal integer
//   o:       The argument is formatted as an octal integer
//   x, X:    The argument is formatted as a hexadecimal integer
//   p:       The argument is formatted as a pointer
//   f:       The argument is formatted as a fixed point decimal
//   e, E:    The argument is formatted in exponential notation
//   g, G:    The argument is formatted as either fixed point or using
//            scientific notation depending on its magnitude
//   c:       The argument is formatted as a character
//   s:       The argument is formatted as a string
//
template<class... T>
void print(std::ostream& os, const char * format, const T&... t)
{
    // 引数をキャプチャする
    print_storage args = { any_printable(t)... };
    // そして実際の実装へ転送する
    print_impl(os, format, args);
}

// このprintのオーバーロードはストリームが指定されない場合にstd::coutへ書き出す。
template<class... T>
void print(const char * format, const T&... t)
{
    print(std::cout, format, t...);
}

// ここからの実装は分割コンパイルが可能である。

// 整数をパースする単項関数
int parse_int(const char *& format) {
    int result = 0;
    while(char ch = *format) {
        switch(ch) {
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
            result = result * 10 + (ch - '0');
            break;
        default: return result;
        }
        ++format;
    }
    return result;
}

// printf 実装 
void print_impl(std::ostream& os, const char * format, const print_storage& args) {
    int idx = 0;
    ios_flags_saver savef_outer(os, std::ios_base::dec);
    bool has_positional = false;
    bool has_indexed = false;
    while(char ch = *format++) {
        if (ch == '%') {
            if (*format == '%') { os << '%'; continue; }

            ios_flags_saver savef(os);
            ios_precision_saver savep(os);
            ios_fill_saver savefill(os);

            int precision = 0;
            bool pad_space = false;
            bool pad_zero = false;

            // 引数インデックスをパースする
            if (*format != '0') {
                int i = parse_int(format);
                if (i != 0) {
                    if(*format == '$') {
                        idx = i - 1;
                        has_indexed = true;
                        ++format;
                    } else {
                        os << std::setw(i);
                        has_positional = true;
                        goto parse_precision;
                    }
                } else {
                    has_positional = true;
                }
            } else {
                has_positional = true;
            }

            // フォーマット修飾子をパースする 
            while((ch = *format)) {
                switch(ch) {
                case '-': os << std::left; break;
                case '+': os << std::showpos; break;
                case '0': pad_zero = true; break;
                case ' ': pad_space = true; break;
                case '#': os << std::showpoint << std::showbase; break;
                default: goto parse_width;
                }
                ++format;
            }

        parse_width:
            int width;
            if (*format == '*') {
                ++format;
                width = any_cast<int>(args.at(idx++));
            } else {
                width = parse_int(format);
            }
            os << std::setw(width);

        parse_precision:
            if (*format == '.') {
                ++format;
                if (*format == '*') {
                    ++format;
                    precision = any_cast<int>(args.at(idx++));
                } else {
                    precision = parse_int(format);
                }
                os << std::setprecision(precision);
            }

            // 型指定子をパース(と無視)する
            switch(*format) {
            case 'h': ++format; if(*format == 'h') ++format; break;
            case 'l': ++format; if(*format == 'l') ++format; break;
            case 'j':
            case 'L':
            case 'q':
            case 't':
            case 'z':
                ++format; break;
            }

            std::size_t truncate = 0;

            // フォーマット記号をパースする
            switch(*format++) {
            case 'd': case 'i': case 'u': os << std::dec; break;
            case 'o': os << std::oct; break;
            case 'p': case 'x': os << std::hex; break;
            case 'X': os << std::uppercase << std::hex; break;
            case 'f': os << std::fixed; break;
            case 'e': os << std::scientific; break;
            case 'E': os << std::uppercase << std::scientific; break;
            case 'g': break;
            case 'G': os << std::uppercase; break;
            case 'c': case 'C': break;
            case 's': case 'S': truncate = precision; os << std::setprecision(6); break;
            default: assert(!"Bad format string");
            }

            if (pad_zero && !(os.flags() & std::ios_base::left)) {
                os << std::setfill('0') << std::internal;
                pad_space = false;
            }

            if (truncate != 0 || pad_space) {
                // これらはstd::setwで取り扱うことができない。stringstreamに書き出して
                // pad/truncate を手動で行う。
                std::ostringstream oss;
                oss.copyfmt(os);
                oss << args.at(idx++);
                std::string data = oss.str();

                if (pad_space) {
                    if (data.empty() || (data[0] != '+' && data[0] != '-' && data[0] != ' ')) {
                        os << ' ';
                    }
                }
                if (truncate != 0 && data.size() > truncate) {
                    data.resize(truncate);
                }
                os << data;
            } else {
                os << args.at(idx++);
            }

            // positionalとindexed argumentsをフォーマット文字列内で同時に持つことはできない。
            assert(has_positional ^ has_indexed);

        } else {
            std::cout << ch;
        }
    }
}

int main() {
    print("int: %d\n", 10);
    print("int: %0#8X\n", 0xA56E);
    print("double: %g\n", 3.14159265358979323846);
    print("double: %f\n", 3.14159265358979323846);
    print("double: %+20.9e\n", 3.14159265358979323846);
    print("double: %0+20.9g\n", 3.14159265358979323846);
    print("double: %*.*g\n", 20, 5, 3.14159265358979323846);
    print("string: %.10s\n", "Hello World!");
    print("double: %2$*.*g int: %1$d\n", 10, 20, 5, 3.14159265358979323846);
}

複数のシグネチャを持つBoost.Function
(この節のコード例のソースはmultifunction.cppを参照のこと)

この例では複数のシグネチャをサポートするBoost.Functionの拡張を実装する。

この例はC++11の機能を使用している。動かすためには比較的新しいコンパイラを使用する必要がある。

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/callable.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/variant.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/range/algorithm.hpp>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>

namespace mpl = boost::mpl;
using namespace boost::type_erasure;
namespace phoenix = boost::phoenix;

// まず初めにmultifunctionテンプレートを宣言する。
// multifunction は Boost.Function に似ているがこれがひとつのシグネチャしか
// 取れないのに対して、いくつでもシグネチャを取ることができる。
template<class... Sig>
using multifunction =
    any<
        mpl::vector<
            copy_constructible<>,
            typeid_<>,
            relaxed,
            callable<Sig>...
        >
    >;

// variantを処理するために multifunction を使ってみよう。
// 簡単な再帰variantを定義することからはじめる。
typedef boost::make_recursive_variant<
    int,
    double,
    std::string,
    std::vector<boost::recursive_variant_> >::type variant_type;
typedef std::vector<variant_type> vector_type;

// ここでvariantの末端ノードに対して演算可能なmultifunctionを定義する。
typedef multifunction<void(int), void(double), void(std::string)> function_type;

class variant_handler
{
public:
    void handle(const variant_type& arg)
    {
        boost::apply_visitor(impl, arg);
    }
    void set_handler(function_type f)
    {
        impl.f = f;
    }
private:
    // boost::apply_visitorと組み合わせて使うクラス
    struct dispatcher : boost::static_visitor<void>
    {
        // 末端用 
        template<class T>
        void operator()(const T& t) { f(t); }
        // vector用、再帰的に要素を演算する
        void operator()(const vector_type& v)
        {
            boost::for_each(v, boost::apply_visitor(*this));
        }
        function_type f;
    };
    dispatcher impl;
};

int main() {
    variant_handler x;
    x.set_handler(std::cout << phoenix::val("Value: ") << phoenix::placeholders::_1 << std::endl);

    x.handle(1);
    x.handle(2.718);
    x.handle("The quick brown fox jumps over the lazy dog.");
    x.handle(vector_type{ 1.618, "Gallia est omnis divisa in partes tres", 42 });
}

コンセプトの定義
コンセプトはanyに格納される型の制約の集合を定義するものである。
コンセプトには三種類ある。

  1. 本ライブラリは事前定義された多くのコンセプトを持っている。これら大半はユーザー定義のコンセプトと同等だが、幾つかのものは特別な扱いを要求する。
  2. ユーザーは自身のプリミティブなコンセプトを以下に示すように定義できる。マクロBOOST_TYPE_ERASURE_MEMBERとBOOST_TYPE_ERASURE_FREEはこの形式のコンセプトを定義する。
  3. 全ての要素にコンセプトを持つMPL Forward シーケンスはこれもまたコンセプトである。これはコンセプトの合成を容易にする。

全てのプリミティブなコンセプトはそれぞれ一つの関数を定義する。プリミティブなコンセプトはクラステンプレートを特殊化してapplyという名前のstaticメンバ関数を持たなければならない。これはcallによってこの関数がディスパッチされるときに実行される。このテンプレートはテンプレート型パラメータのみ受け取ることができ、非型テンプレートパラメータやテンプレート・テンプレートパラメータは許可されない。

コンセプトのこのテンプレートパラメータはplaceholderを含むかもしれない。以下のことが考えられる。

  • それぞれのテンプレート引数は cv修飾 かつ/または 参照修飾 されたplaceholder型かもしれない。
  • もしテンプレート引数が関数型ならばその引数と戻り値型はcv/参照 修飾されたplaceholderかもしれない。

これ以外のplaceholderは無視される。

コンセプトはanyを生の値から構築するかbindingを構築することによりインスタンス化される。コンセプトが特定の型バインディングの集合でインスタンス化されるときそれぞれのplaceholderは非cv修飾で非参照な型へバインドされる。テンプレート引数リスト内のplaceholderがバインドされる型にそれぞれ置き換えられた後、以下のことが守られる。

  • バインドされるコンセプトのapplyの引数の数はバインド元のコンセプトの引数と同じでなければならない。
  • バインドされるコンセプトのapplyの引数と戻り値はバインド元のコンセプトの対応する引数と戻り値から以下のように継承できる。もしバインド元のコンセプトの引数が任意のcvと参照修飾子を持つplaceholderならば、バインドされるコンセプトの引数はplaceholderを置き換える事ができる。それ以外の場合、バインド元のコンセプトの引数はバインドされるコンセプトの引数と同じでなければならない。
// 正しい。
template<class T = _self>
struct foo1 {
  static void apply(const T& t) { t.foo(); }
};

// 間違い。applyのシグネチャがプライマリテンプレートのものと異なる。
template<>
struct foo1<int> {
  static void apply(int i);
};

// 間違い。コンセプトはテンプレートでなければならない。 
struct foo2 {
  static void apply(const _self&);
};

// 間違い。applyはstaticでなければならない。
template<class T = _self>
struct foo3 {
  void apply(const T&);
};

// 間違い。applyはオーバーロードできない。
template<class T = _self>
struct foo3 {
  static void apply(T&);
  static void apply(const T&);
};

// 間違い。最上位のplaceholdersしか見つからない。
template<class T>
struct foo4;
template<class T>
struct foo4<boost::mpl::vector<T> > {
  static void apply(const T&);
};

// 間違い。テンプレートのテンプレートパラメータは許可されない。
template<template<class> class T>
struct foo5
{
    static void apply(T<int>&);
};

事前定義されたコンセプト
下の表においてTとUは演算を適用する型である。Rは戻り値である。Tの規定値は常にanyのデフォルトの挙動に適合する_selfである。これらのコンセプトは普通のセマンティックスを想定している。つまり比較オペレータは常にboolを返し、引数と戻り値には適切に参照が追加される。

注意書きされている場合を除いて、本ライブラリによって定義されたプリミティブコンセプトはコンセプトマップを提供するために特殊化することができる。copy_constructibleやイテレータコンセプトは合成されているので特殊化することはできない。 constructible, destructible, typeid_, same_typeはライブラリ内で特別な扱いを要求するため特殊化できない。

表 33.1. 特殊メンバ

concept notes
constructible<Sig> -
copy_constructible<T> -
destructible<T> -
assignable<T, U = T> -
typeid_<T> -

表 33.2. 単項演算子

operator concept notes
operator++ incrementable<T> 独立した後置インクリメントはない
operator-- decrementable<T> 独立した後置ディクリメントはない
operator* dereferenceable<R, T> Rは一般に参照であるべき
operator~ complementable<T, R = T> -
operator- negatable<T, R = T> -

表 33.3 二項演算子

operator concept notes
operator+ addable<T, U = T, R = T> -
operator- subtractable<T, U = T, R = T> -
operator* multipliable<T, U = T, R = T> -
operator/ dividable<T, U = T, R = T> -
operator% modable<T, U = T, R = T> -
operator& bitandable<T, U = T, R = T> -
operator| bitorable<T, U = T, R = T> -
operator^ bitxorable<T, U = T, R = T> -
operator<< left_shiftable<T, U = T, R = T> -
operator>> right_shiftable<T, U = T, R = T> -
operator== and != equality_comparable<T, U = T> !=は==を用いて実装される
operator<, >, <=, and >= less_than_comparable<T, U = T> すべては<から実装される
operator+= add_assignable<T, U = T> -
operator-= subtract_assignable<T, U = T> -
operator*= multiply_assignable<T, U = T> -
operator/= divide_assignable<T, U = T> -
operator%= mod_assignable<T, U = T> -
operator&= bitand_assignable<T, U = T> -
operator|= bitor_assignable<T, U = T> -
operator^= bitxor_assignable<T, U = T> -
operator<<= left_shift_assignable<T, U = T> -
operator>>= right_shift_assignable<T, U = T> -
operator<< ostreamable<Os = std::ostream, T = _self> -
operator>> istreamable<Is = std::istream, T = _self> -

表 33.4 その他の演算子

operator concept notes
operator() callable<Sig, T> Sigは関数型でなければならない. Tはconst修飾されるかも知れない
operator[] subscriptable<R, T, N = std::ptrdiff_t> Rは一般に参照になるべき。Tはconst修飾することもできる。

表 33.5 イテレータコンセプト

concept notes
iterator<Traversal, T, Reference, Difference> イテレータの値型を制御するにはsame_typeを使用する。
forward_iterator<T, Reference, Difference> -
bidirectional_iterator<T, Reference, Difference> -
random_access_iterator<T, Reference, Difference> -

表 33.6 特殊なコンセプト

concept notes
same_type<T> 二つの型が同じ型であることを示す

リファレンス
(原文へ)


根拠

なぜデストラクタの存在を明示的に指定しなければならないのか?
参照を使用するときにはデストラクタは不要である。暗黙的に指定しないことでprivateまたはprotectedなデストラクタを持つ型を参照でキャプチャすることが可能になる。一貫性のために値でキャプチャするときも同様に指定しなければならない。

なぜ非メンバ関数なのか?
anyのメンバはカスタマイズされうる。フリー関数を使用することによって我々はユーザーがしたいことを何も邪魔しないことを保障できる。

なぜplaceholderが_a,_bという名前で_1,_2ではないのか
本ライブラリの初期バージョンでは_a,_bなどの代わりに_1,_2などの名前を使用してた。これは一定の混乱を引き起こす。なぜなら番号のplaceholderはすでに幾つかのBoost/Std Bind, Boost.Phoenix, Boost.MPLを含む他のライブラリにおいて少し違った別の意味で使用されているからである。私は最終的にこのplaceholderは位置パラメータよりも名前つきパラメータに相当しているため、番号よりも文字の方がより適切だと判断した。

参照にboost::refを使ったらどうか?
Boost.Functionはboost::refを使うことにより関数オブジェクトに参照を格納することを可能にする。しかしながら、一般的なケースでは参照と値を同じ方法で扱うことは一貫性に欠けた理解するのが難しい挙動を引き起こす。もしBoost.TypeErasureがこのように参照を扱った場合、あなたがanyをコピーしたとき新しいオブジェクトが本当の複製なのか同じ基礎オブジェクトへの単なる新しい参照なのかどうか見分けがつかなくなる。Boost.Functionはこのことを考えなくても良い。なぜならば格納された関数オブジェクトに対する変更を伴う操作はなにも公開されないからだ。

他に提案されていた方法は初回のみ参照を維持するものだ。

int i = 2;
any x = ref(i);
any y = x; // makes a copy

残念ながらこれは全ての利用法をカバーできない。このような参照を関数から返す信頼できる方法がないのだ。加えて望む望まないにかかわらず参照かどうかを追跡するフラッグを追加する必要がありオーバーヘッドが加わる。(これをvtableの"clone"メソッドに保持する代替方法はBoost.TypeErasureが使用する分離されたvtableを考えると実装が途方もなく複雑になる上依然としてオーバーヘッドがある。)

将来
幾つかのアイディアがある。これらが将来実装される保障はどこにもない。

  • SBOの使用
  • vtableのレイアウトについてより細かい制御を可能にする
  • 変換の際にサブテーブルの再利用を試みる
  • "dynamic_cast"を可能にする。これはコンセプトマッピングの大域レジストリの作成を要求する。
  • コンパイル時間コストの最適化

謝辞
anyという名前と私のplaceholderシステムの祖先はAlexander Nasonov作の DynamicAnyによる。

レビューマネージャのLorenzo Caminitiと正式レビューに参加してくれた全ての皆さんに感謝する。

Christophe Henry
Paul Bristow
Karsten Ahnert
Pete Bartlett
Sebastian Redl
Hossein Haeri
Trigve Siver
Julien Nitard
Eric Niebler
Fabio Fracassi
Joel de Guzman
Alec Chapman
Larry Evans
Vincente J. Botet Escriba
Marcus Werle
Andrey Semashev
Dave Abrahams
Thomas Jordan

関連するもの
似たライブラリが幾つか存在する。私の知る限り3つある。

  • Boost.Interfaces by Jonathan Turkanis
  • Adobe Poly
  • Boost.dynamic_any by Alexander Nasonov

正規表現の正規表現をboost.xpressiveで記述する

正規表現の文字列を正規表現ライブラリへ渡す前にフィルタリングしたくなったので正規表現自体の正規表現を書いてみました。
つまり事前に必要の無い表現を弾いたり、新たな表現を追加したりなんて事がしたいわけです。
記述に当たって普通の正規表現で書こうとすれば混乱しそうだったのでxpressiveのstatic regexを使用しました。
基本的な表現はサポートしているので必要に応じて拡張してみてください。
以下の例では独自の表現[:cat:]がneko|cat|kittyにマッチするようにしています。また\dという表現を見つけた場合例外を投げるようにしてみました。

#include <string>
#include <iostream>
#include <algorithm>
#include <boost/xpressive/xpressive.hpp>
using namespace boost::xpressive;

sregex GetRegexOfRegex() {
    sregex regexofregex, anchors, wildcard, characlass, collating, equivalence, normal, 
        escape, setitemchara, chara, setitem, posset, negset, charaset, group, nonmarkgroup, comment, element, basic;

    anchors = as_xpr('^') | '$';
    wildcard = as_xpr('.');

    characlass = (s1 = as_xpr('[') >> ':' >> +alpha >> ':' >> ']'); //ここでs1にキャプチャー
    collating = as_xpr('[') >> '.' >> +alpha >> '.' >> ']'; 
    equivalence = as_xpr('[') >> '=' >> +alpha >> '=' >> ']'; 

    normal = ~(set='^', '$', '\\', '.', '(', ')', '?', '+', '*', '[', ']', '|', '{', '}', '-');
    escape = (s2 = '\\' >> _);//ここでs2にキャプチャー
    setitemchara = escape | normal | characlass | collating | equivalence;
    chara = setitemchara | '-';

    setitem = (setitemchara >> '-' >> setitemchara) | setitemchara;
    posset = '[' >> +setitem >> ']';
    negset = as_xpr('[') >> '^' >> +setitem >> ']';
    charaset = posset | negset;

    group = as_xpr('(') >> !by_ref(regexofregex) >> ')';
    nonmarkgroup = as_xpr('(') >> '?' >> ':' >> !by_ref(regexofregex) >> ')';
    comment = as_xpr('(') >> '?' >> '#' >> *~(set=')') >> ')';

    element = wildcard | anchors | chara | charaset | group | nonmarkgroup | comment;

    basic = element >> !((as_xpr('*') | '+' | '?' | ('{' >> +_d >> !(',' >> *_d) >> '}')) >> !(as_xpr('?')|'+'));
    regexofregex = +basic >> *('|' >> +basic);
    return regexofregex;
}

struct escape_unsupported {};

struct EditRegex {
	EditRegex(const smatch& m, std::string& dest):buf(dest),lastitr(m[0].first) { 
            (*this)(m);
            buf.append(lastitr, m[0].second);
        }
private:
	void operator () (const smatch& result) {
                //s1 独自の表現[:cat:]を普通の正規表現(?:neko|cat|kitty)へ展開
		if (result[1].matched && result[1].str() == "[:cat:]") {
			buf.append(lastitr, result[1].first);
			lastitr = result[1].second;
			buf.append("(?:neko|cat|kitty)");
		}
                //s2 \dを弾いてみる
                if (result[2].matched && result[2].str() == "\\d") {
			throw escape_unsupported();
		}

		struct myref {
			void operator()(const smatch& result) { er(result); }
			EditRegex& er;
		} me = {*this};
		std::for_each(result.nested_results().begin(), result.nested_results().end(), me);
	}
	std::string& buf;
	std::string::const_iterator lastitr;
};

void test() {
    std::string input = "^a*ab.c|ef+(g[^hi])?$(?:(?#123)[:cat:]opq+?st{2,})";
    try {
        smatch result;
        if (!regex_match(input, result, GetRegexOfRegex())) {
            std::cout << "not matched\n";
            return;
        }
        std::string buffer;
        EditRegex(result, buffer);
	std::cout << buffer << std::endl;
    } catch (...) {
        std::cout << "error\n";
    } 
}

出力

^a*ab.c|ef+(g[^hi])?$(?:(?#123)(?:neko|cat|kitty)opq+?st{2,})

メモ
sregexを複数組み合わせているためsmatchがネストしている。
sub_match.first, sub_match.secondで該当箇所のイテレータが取れるのでそれを利用して編集している。
NFA正規表現一般の話になりますが書き方によってはバックトラッキングにより実用できないほど遅くなるので注意が必要。その場合適宜 keep() を使用してバックトラッキングを抑止する必要があるかも。

似た構文でSpirit.Qiにパーサーを流用できるのでそっちの方が速くて確実だと思う。

boost::graph グラフコンテナと共に頂点記述子もコピーする

adjacency_listのグラフをコピーする際に注意することがあります。
VertexListにlistSなど指定しているとvertex_descriptorはコピー先で使用できないということです。vecSの場合vertex_descriptorは整数インデックスなので問題ないと思いますが他はポインタのようなものなので使用できません。当たり前の話ですが少し嵌ってしまいました。

そこでコピー元に対応するコピー先のvertex_descriptorをどうやって取得したらいいのかということですが、
copy_graph関数をorig_to_copyパラメータと共に使用します。
これで全ての頂点に対してコピー元とコピー先のvertex_descriptorペアが取得できます。

#include <map>
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/copy.hpp>
#include <boost/property_map.hpp>
 
using namespace boost;
int main() {
    typedef adjacency_list<listS, listS, directedS> Graph;
    typedef Graph::vertex_descriptor Vertex;
    Graph g(5), h;
 
    typedef std::map<Vertex, Vertex> Map; //結果を格納するコンテナ unordered_mapなどでもよい。
    Map m;
    associative_property_map<Map> pm(m); //associative_property_mapでラップする
    copy_graph(g, h, orig_to_copy(pm)); //グラフをコピーしながら、orig_to_copyで全ての対応するvertex_descriptorペアを取得
 
    for (Map::iterator p = m.begin(); p != m.end(); ++p) {
        std::cout << p->first << " -> " << p->second << std::endl;
    }
}
0x80f0008 -> 0x80f00e0
0x80f0030 -> 0x80f0128
0x80f0058 -> 0x80f0170
0x80f0080 -> 0x80f01b8
0x80f00a8 -> 0x80f0200