C++とUnicode, char8_t

char8_t

 2018年11月上旬に開催されたC++のSan DiegoミーティングにおいてUTF-8専用の型であるchar8_tの仕様が固まり、C++20のドラフトにマージされました(文書番号N4791以降)
 Cとの同期という受動的な理由でchar16_t型とchar32_t型とがC++に入って以降、C++独自にchar8_t型を追加しようという試みはこれまでにも何度かありました。なぜそれらは受理されず、なぜ今回は受理されるに至ったのでしょうか。これまで個人的に見聞きしてきた経験から、C++におけるUnicode対応が遅々として進まない背景について少し綴ってみたいと思います。

目次

C++への機能追加はどのようにして行われるか

 2019年現在、C++というプログラミング言語の仕様策定はISO/IEC JTC1/SC22/WG21にて行われています。Unicodeに詳しい方ならISO/IEC JTC1という文字列には見覚えがあるかもしれません。ISO/IEC 10646(Unicodeのコードチャート本体)を策定しているSC2/WG2と同じISO/IEC JTC1の下に、C++などプログラミング言語の委員会SC22/WG21も設置されています。
 ただ同じ組織に属しているとはいえ、SC2/WG2とSC22/WG21とでは関わっている人間も違う上、空気もかなり異なります。

 SC22/WG21のサイトThe C++ Standards Committeeには、投稿されてきた様々な種類の文書が一定の期間ごとに mailing という形で公開されます。例えば2019年1月現在における最新のリストはこちらです。このうち文書番号がNで始まっているものは規格策定作業そのものに関連した文書で、Pで始まっているものが提案書です。ご覧の通り毎回大量の提案が寄せられています(以前はすべてN~という形式でしたが、2015年9月より提案書はP~という形式になりました。重要な文書が大量の提案書に埋もれてはまずいとの判断なのかもしれません)。

 現在C++の作業部会の会合は年3回のペースで開かれています。提案者になると各提案の状態が確認できるようになるのですが、C++の会議は毎回時間不足のためすべての提案について議論できていません。そのためか今は提案者本人ないしその代理人によって、委員たちの前で直接プレゼンをしてそのままその場でディスカッションできる提案が優先して議論される傾向にあります。
 私の場合、std::regexにmultilineオプションを追加する提案を出した時は、LEWG(Library Evolution Working Groupの略。ライブラリの拡張を議論する作業部会)の当時のChairが会議直前に「自分でプレゼンしますか? 無理ならこちらで代理人を探してみますのでそう言ってください」と打診してくださったことに加え、運良く代理でプレゼンしてくれる人が現れてくださったおかげで、めでたく議題に加えてもらうことが出来ました。小規模な機能追加だったこともあってか特に反対意見もなく、提案自体はわりとあっさり受理されたものの、その際、代理人の方から言い回しについて修正を求められました。この時はじめて認識したのですが、C++では現行の仕様書との差分も提案者が最後まで責任を持って執筆する仕組みなのです。
 mailing の提案書には、必ずと言って良いほど「規格書のここにこう加筆して、ここを削除する」という記述が含まれています。あれは「こんな感じに変更しましょう。言い回しなど細かい修正が必要ならそちらで適宜変えてください」という例示ではなく、「きっちりこの通り変更しましょう」という意味なのです。そのため提案が受理されても、規格書に載せられるレベルの文面になるまで提案者は何度でも書き直しをさせられます。

 つまりC++の場合、作業部会に「こういう機能を追加してほしい」と言うだけではダメなのです。その機能を追加するにあたって規格書のどこをどのように修正する必要があるかを調べ、その機能が入るとC++のどの部分にどのような影響を与える可能性があるかを洗い出し、実際に規格書に書き入れる文章を考えてペーパーを提出し、その上で委員の了承を取り付ける、提案者はここまでする必要があるのです。委員会の中に事務的なことをしてくれる人がいて、その人が最終的な文面は調整してくれる……などという仕組みにはなっていません。言い出しっぺである提案者自身が最後まで責任を負わないとならないのです(ISO/IEC 10646は逆に、提案した文字が受理されたら提案者はその後もう何も関われません)。

 結局のところ、これまでchar8_tを含めたUnicode関連の提案がなかなか受理されなかったのも、「作業部会で提案書のプレゼンをして委員と質疑応答してその際出たコメントや駄目出しされた部分を直したり反映させたりした改訂版を再び提出し、それを元に次の会議でまたプレゼンして委員と質疑応答して……」ということを提案が受理されるまで根気良く行ってくれる人がいなかったということに尽きます。
 そして今回char8_tが正式に受理されたのは、Tom Honermannという方がC++の委員会内にSG16というUnicode専門の部会 (Study Group) を作って、粘り強く「P0482 char8_t: A type for UTF-8 characters and strings」という提案書を改訂してくれたおかげです。char8_tの採用自体は2018年3月のJacksonville会議で大筋合意に至っていたのですが(ただし「強い反対票」が最後まで残った)、その後も言い回しの調整作業が続き、最終的に受理されたのはR6 (Revision 6) でした。改訂番号の大きさにこの提案が難産だったことがよく現れています。

 なおchar8_tがC++20に入ることが決まったのに併せて、従来char型用であったu8というprefixもchar8_t型用に変わることになります。この変更については2018年の終わり頃SG16内で異論が出て、その際char8_t用には別のprefixを新規に導入することも検討されたようですが、結局SG16としては新しいprefixの導入を提案しない(u8をchar8_t用に変更する)という方針で行くことにしたようです。

今後C++のUnicode対応は進むか

 Honermann氏によると今回の会議では次のような提案についても進展があったそうです。

※Unicode/10646関連ではこの他にも「参照している10646が古すぎる(1993年版。Plane 1以降が使われるようになるはるか前)」「Normative referencesにUnicode規格も追加すべし」などの意見があったのですが、前者については既にN4762で対応され(ただしdeprecated扱いとなっている<codecvt>用に、1993年版も最新版と併記する形で規格書に残った)、後者についてはUnicodeにしかない機能を入れることになった段階で追加するという話になっています。

 現時点でC++のUnicode対応は他の言語に比べて大きく後れを取っていますので、仮にこれらがすべてC++20に間に合ったとしても物足りない印象なのはどうにも否めません。
 SG16の今後の活動方針についてはP1238に記されています。それによるとC++20に関しては優先して取り組むものを既に絞り込んだようですので、本格的なUnicode対応ライブラリの整備はその後、早くともC++23以降ということになりそうです。

 これまではUnicode関連の提案をすると提案者がC++の作業部会(EWG, LEWGなど)で孤軍奮闘するような形になってしまっていましたが、SG16が設置されたことにより、今後Unicode関連の提案はまずSG16に送られてそちらで議論されるようになることが予想されます。そこで承認を取り付けることが出来れば、「既にSG16で議論されたものだから」ということでC++の作業部会ではそれほど突っつかれずに了承してもらえるようになるかもしれません。
 さらには、C++のSG一覧頁によりますとC++11以来の懸案であったConcepts (SG8)やRanges (SG9)を始め、SG2 Modules、SG3 File System、SG4 Networkingなどが一段落ついて休眠状態に入ったことも追い風と言えるかもしれません。これまでの会議ではこれらにかなりの時間や人員を割いていたように見受けられましたので、今後はSG16を含む他の分野に時間を回してもらえるようになる可能性があります。

 一方で不安要素もあります。Unicodeは文字コード表の他にも関連する技術文書がいくつもあり、それらに付随しているデータベースも含めるとかなり膨大かつ複雑な規格です。C++のライブラリを作る人たちすべてがUnicodeに精通しているとは限りませんので、あまり複雑な機能を標準ライブラリに入れてしまいますと実装が進まなかったりバグの温床になってしまったりする恐れがあります。
 P1238にもそのあたりを意識した文言が織り込まれていますが、今後SG16がUnicodeライブラリの整備に本格的に取り掛かるようになった時、「標準ライブラリに求めるもの」を巡ってメンバー間の温度差が表面化してくる可能性もあります。

 個人的には、C++はまだコードポイント単位で文字を切り出すことすら出来ないのに、Grapheme Cluster(人間が一文字と見なす文字図形を構成するコードポイントの連続)などという言葉がSG16の議事録にちらほら出てくる辺りに不安を感じています。最初からあまり欲張らず、当面は他の言語に追い付くことを目指してもらいたいところです。

C++におけるstd::regexのUnicode対応

 multilineオプションが受理された後、std::regexのUnicode対応を進めるべくstd::regexをchar16_t/char32_t対応にする提案も出したことがあるのですが、こちらは代理でプレゼンしてくれる人が現れなかったため、残念ながら長らく宙ぶらりんにされた末、2018年11月のSan Diego会議直前に rejected とマークされてしまいました。
 一応LEWGの前のChair(multilineの時打診してくれた方)がSG16の前身へ提案書を転送しておいてくださったため、こういう提案があったこと自体はSG16のほうでも認識してもらえているようです。テキスト処理をする上で正規表現というのは重要なものでしょうから、SG16の動向次第では再起を図れればと考えています。

 Unicode関連の動きがありましたら加筆するかもしれません。