最終更新日時:
が更新

履歴 編集

#embedにoffsetパラメータを追加 [P3540R3](C++29)

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

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

概要

C++29では、C++26で導入されたファイルを読み込む#embed命令のパラメータとして、リソースの先頭から指定した要素数を読み飛ばすoffsetが追加される。

constexpr unsigned char arr[] = {
#embed "data.bin"
};

constexpr unsigned char offset_arr[] = {
#embed "data.bin" offset(2)  // 先頭2バイトを読み飛ばす
};

static_assert(arr[2] == offset_arr[0]);
static_assert(arr[3] == offset_arr[1]);

ヘッダ部分を読み飛ばしてデータ本体だけを埋め込む、といった用途に使用できる。この機能は、GCCとClangがベンダーパラメータgnu::offsetclang::offsetとして実装していた既存の拡張を、標準のパラメータとして採用したものである。

仕様

  • offset(定数式)は、リソースの先頭から読み飛ばす要素数を表す。offsetパラメータは、1つの#embed命令に一度までしか指定できない
  • 定数式は、値が0以上の汎整数定数式であること。0を指定した場合はなにも読み飛ばされない
  • リソースのサイズ以上の値を指定した場合、リソースは空として扱われる(if_emptyパラメータが適用される)
  • offsetは、limitパラメータの適用前の、リソース本来のサイズに対して適用される。両方を指定した場合、埋め込まれる要素数は「offsetで読み飛ばした残りの要素数」とlimitの値の小さいほうとなる
    constexpr unsigned char offset_limit_arr[] = {
    #embed "data.bin" offset(1) limit(1)  // 2バイト目の1バイトだけを埋め込む
    };
    
    static_assert(arr[1] == offset_limit_arr[0]);
    
  • 機能テストマクロ__cpp_pp_embedの値が202606Lに更新される

// ABCDEF
#include <iostream>

// このファイル自身をリソースとして埋め込む
constexpr unsigned char arr[] = {
#embed __FILE__ limit(9)
};

constexpr unsigned char offset_arr[] = {
#embed __FILE__ offset(3) limit(6)
};

int main()
{
  // offset(3)によって、先頭の「// 」が読み飛ばされる
  static_assert(offset_arr[0] == 'A');
  static_assert(arr[3] == offset_arr[0]);

  for (unsigned char c : offset_arr) {
    std::cout << c;
  }
  std::cout << std::endl;
}

出力

ABCDEF

この機能が必要になった背景・経緯

offsetパラメータは、#embedがC23に採用された後になってユーザーから要望されたため、#embed本体(C++26ではP1967R14)とは別に標準化されることになった。要望を受けてGCCとClangはそれぞれgnu::offsetclang::offsetというベンダーパラメータとして先行実装しており、広く使われていたため、この既存の実装の動作(limitより先に適用される、リソースのサイズ以上なら空になる等)をそのまま標準のパラメータとして採用した。

関連項目

参照