最終更新日時(UTC):
が更新

履歴 編集

文字・文字列リテラル中の数値・ユニバーサルキャラクタのエスケープに関する問題解決 [P2029R4](C++23)

このページはC++23に採用された言語機能の変更を解説しています。

のちのC++規格でさらに変更される場合があるため関連項目を参照してください。

概要

文字リテラル・文字列リテラル中の数値エスケープ (8進エスケープ\ooo、16進エスケープ\xhh) およびユニバーサルキャラクタ名 (\u\U) の仕様には、いくつかの曖昧さや欠陥があった。この変更は、それらをコア言語の問題を解決する。主な内容は以下:

  • 数値エスケープをu8/u/U文字リテラルでも使用できることを明確化する
  • 数値エスケープは、リテラルの文字エンコーディングへの変換対象とならず、コードユニットの値を直接指定する
    • たとえばu8"\xc3\x80"は、2バイトのコードユニット列0xC3, 0x80をそのまま表す (0xC30x80を個別のコードポイントとみなしてUTF-8に再エンコードするわけではない)
  • 複数のコードユニットを必要とする文字は、文字リテラルには書けないが文字列リテラルには書けることを明確化する
    • 文字リテラルにそのような文字を指定した場合は「非エンコード文字リテラル (non-encodable character literal) 」となり、条件付きサポートで型はintとなる。
  • 範囲外の数値エスケープの動作を規定する
    • 通常の文字・文字列リテラルおよびワイド文字・文字列リテラルにおいて、数値エスケープが指定する値がコードユニット型の表現範囲を超える場合、その値が対応する符号なし型の範囲に収まるなら整数変換と同様にコードユニットを初期化し、そうでなければ不適格とする

これらの仕様はGCCやClangの既存の実装に沿ったものであり、主にMicrosoft Visual C++のu8リテラルにおける数値エスケープの扱いに影響する。

#include <cstddef>

int main()
{
  // u8文字列リテラル中の16進エスケープは、UTF-8のコードユニット値を直接指定する
  // (ソースのコードポイントとして再エンコードされない)
  constexpr const char8_t a[] = u8"\xc3\x80"; // バイト列 0xC3, 0x80
  static_assert(sizeof(a) == 3);
  static_assert(a[0] == 0xC3 && a[1] == 0x80 && a[2] == u8'\0');

  // これはU+00C0 (À) のUTF-8エンコーディングと一致する
  constexpr const char8_t b[] = u8"À";
  static_assert(sizeof(b) == sizeof(a));
  static_assert(b[0] == a[0] && b[1] == a[1]);

  // 16進・8進エスケープはu8/u/U文字リテラルでも使用できる
  static_assert(u8'\x41' == u8'A');
}

出力

関連項目

参照