SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

【C++の新機能を理解する】最新バージョンを徹底解説!

C++の新機能を理解する──静的なoperator()/operator[]と多次元対応operator[]など言語仕様の強化

【C++の新機能を理解する】最新バージョンを徹底解説! 第2回

assume属性

 C++23では、コンパイラに対して最適化のヒントを与える [[assume]]属性が導入されました。これにより、特定の条件下での実行速度の向上や、バイナリサイズの削減(コンパクト化)が可能になります。

 [[assume]] 属性は、コード上の特定の箇所において「ある条件が必ず真である」ことをコンパイラに伝えます。これは特定の関数や変数に付与するのではなく、以下のように「空の文」に対して記述します。

リスト assume_attr.cpp
int divide_by_64(int x)
{
  [[assume(x >= 0)]];	// xが0以上であることを仮定する
  return x / 64;
}

 この属性は、引数の式がtrueに評価されることを期待します。もしfalseに評価される場合には、結果は不定となります。コンパイラに最適化(gccなら-O3オプションなど)を指示し実行すると、以下のリストのコードは、最初のcoutは問題なく出力されますが、2番目のcoutでは何も出力されません。

 このように出力が消失する可能性があるだけでなく、プログラムがクラッシュする可能性もあるなど、仮定から外れたコードは予期せぬ結果を招くことを押さえておいてください。

リスト assume_attr.cpp
cout << divide_by_64(64) << endl;	// 期待通り:2
cout << divide_by_64(-64) << endl;	// 期待外れ:何も出力されない

アセンブリレベルでの最適化

 なぜこのようになるのかは、アセンブリコードを出力させてみると分かります(gccでは-Sオプション)。以下のリストは、assume属性なしとありの場合のアセンブリコード出力です。

リスト assume_attr.s(assume属性なし)
_Z12divide_by_64i:
.LFB4083:
    .seh_endprologue
    testl   %ecx, %ecx		; 引数(被除数)が負数であるかの判定
    leal    63(%rcx), %eax	; 負数の場合の補正値をあらかじめ用意しておく
    cmovns  %ecx, %eax		; 正数ならそのまま使う
    sarl    $6, %eax		; 算術的右シフト(6ビット)
    ret

 除算においては、被除数が負である場合に期待する結果を得るために、除数から1を引いた数(ここでは63)をあらかじめ被除数に加えるという前処理が必要です。これに対して、assume属性ありの場合は以下のリストのようになります。

リスト assume_attr.s(assume属性あり)
_Z12divide_by_64i:
.LFB4083:
    .seh_endprologue
    movl    %ecx, %eax
    sarl    $6, %eax	; 補正なしで即座に右シフト
    ret

 assume属性により被除数が0以上であることが仮定されているので、負数である場合の前処理が省かれています。これにより、マシンコードがコンパクトになり、かつ不要な計算処理がなくなることによる速度向上が期待できます。

式評価の副作用

 [[assume]]属性の中に記述された式は、最適化のヒントとしてのみ利用され、実際に実行(評価)されるわけではありません。そのため、式の中で変数を操作しても副作用は発生しません。

リスト assume_attr.cpp
int as_is(int x)
{
  [[assume(++x == 64)]];	// xはインクリメントされない
  return x;
}

 この例では、コンパイラは「この関数が呼ばれるとき、++xが64になる(=つまりxは63である)」と仮定して最適化を行います。結果として、「return x;」は単に定数63を返すコードに置き換わる可能性があります。

エスケープシーケンスの区切り文字

 C++ 23では、文字列リテラル中で8進数や16進数などで文字を指定する際に文字波括弧{}で囲む区切り文字が利用可能になりました。これにより、エスケープシーケンスの範囲が明確になり、記述の曖昧さが排除されるとともに可読性が向上しています。

 これまでは、8進数や16進数で文字を表現する場合、以下のルールに従う必要がありました。

リスト escape_sequence.cpp
cout << "\100\608\1000" << endl;	// 8進数:\に続く1~3桁
cout << "\x45\x56" "7" << endl;		// 16進数:\xに続く任意の桁(型による制限あり)
auto str1 = u8"\U0001F1FA";
cout << reinterpret_cast<const char*>(str1) << endl;	// Unicode:\u(4桁)、または\U(8桁)
図 従来のエスケープシーケンスでの出力結果
図 従来のエスケープシーケンスでの出力結果

 しかし、これらのルールには以下の不便さがありました。

  • 8進数:3桁に達するか、0~7以外の文字が出現するまでを範囲とするため、後続の文字との区別がつきにくい。
  • 16進数:16進数として解釈可能な文字(0-F)が続く限り、どこまでもエスケープシーケンスと見なされる。そのため、直後に「7」という文字を置きたい場合、コード例のように文字列リテラルを一度区切る必要があった。
  • Unicode:コードポイントが5桁の場合でも、上位桁を0で埋めて8桁(\U)にする必要があった。

 こういった背景から、C++ 23では、エスケープシーケンスの範囲を明確にできる区切り文字「{ }」が利用可能になりました。上記のリストは、以下のように書き換えることができます(出力結果は同じ)。

リスト escape_sequence.cpp
cout << "\o{100}\o{60}8\o{100}0" << endl;	// 8進数:\o{ }を使用
cout << "\x{45}\x{56}7" << endl;	// 16進数:\x{ }を使用(後続の文字"7"と混同されない)
auto str2 = u8"\u{1F1FA}";	// Unicode:\u{ }を使用(桁数の固定が不要)
cout << reinterpret_cast<const char*>(str2) << endl;

 8進数の場合は、新たに導入された\oを前置することに注意してください。これにより、どこまでが数値指定なのかが一目でわかるようになり、Unicode指定においてもゼロ埋めの手間がなくなりました。

名前付きユニバーサルキャラクタ名

 Unicodeに関連して、C++23ではコードポイントの代わりに「キャラクタ名」で指定できる \N{ } も導入されました。

リスト escape_sequence.cpp
auto str3 = u8"\N{LATIN SMALL LETTER A WITH BREVE}\N{COMBINING ACUTE ACCENT}";
cout << reinterpret_cast<const char*>(str3) << endl;
図 名前付きユニバーサルキャラクタ名の出力結果
図 名前付きユニバーサルキャラクタ名の出力結果

 これによって、難解なコードポイントの数値を調べることなく、標準的な名称を用いてUnicode文字を埋め込むことが可能になりました。利用可能な名前の種類は膨大なので、詳細はUAX44-LM2などを参照してください。

まとめ

 今回は、C++ 23における言語仕様面の強化/変更点を、静的なoperator()/operator[]、多次元対応operator[]、assume属性、エスケープシーケンスの区切り文字を中心に紹介しました。

 次回は、Rangesライブラリと、コルーチンベースのジェネレータstd::generatorを紹介します。

この記事は参考になりましたか?

【C++の新機能を理解する】最新バージョンを徹底解説!連載記事一覧
この記事の著者

WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/23296 2026/02/16 08:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング