
2026/03/11 16:27
**タイトル:** C++26:オックスフォード可変長コンマ --- 議論は、C++26で提案されている *オックスフォード可変長コンマ* に焦点を当てています。 これは、パック展開の後に任意の末尾カンマを許容するものです。 ### 現状(C++20) パック展開 (`f(x...)`) の直後には末尾カンマが認められていません。 ### 提案された変更点 末尾カンマを許可し、例えば `f(x...,)` と書くことができるようにすることで、 読みやすさの向上と差分(diff)作業の容易化を図ります。 #### 主なメリット - 末尾カンマが許容されている他の文脈との一貫性が取れる。 - パラメータリストを出力するコード生成ツールが簡素化できる。 - 前行を編集せずに新しい要素を追加しやすくなる。 #### 考慮すべき懸念点 - 既存の文法規則との相互作用と後方互換性への影響。 - コンパイラ実装時の複雑さ。 - パック展開内でのコンマ演算子との曖昧さが生じる可能性。 委員会はトレードオフを検討し、最終的なC++26仕様に反映する前にコミュニティからのフィードバックを求めています。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
(欠落していた詳細を追加)
要約
C++26 は、ellipsis‑only 関数宣言構文(
void foo(int...);)を非推奨にし、標準的なカンマ区切り形式(void foo(int, ...);)と単独の ellipsis 形式(void f(...);)は残すことになります。この変更は提案 P3176R1(「Oxford variadic comma」)の一部であり、C の互換性を向上させ、テンプレートパラメータパックとの混乱を減らし、将来の言語拡張に余地を残すことを目的としています。
現在は両方の形式が許可されています:C 互換の
void foo(int, ...); と、一部の古いコードでまだ使用されている legacy ellipsis‑only 形式です。C ではカンマを省略できません(例:int printf(char*, ...);)。非推奨化は既存プログラムを壊すことはなく、コンパイラは単に ellipsis の前にカンマを追加するか、警告を出すだけで済みます。
曖昧さは
T... が「1 つのパラメータに ellipsis を付けたもの」か「テンプレートパラメータパック」を表す可能性があるため生じます(例:void g(auto... args) と void g(auto args...))。現在最も奇妙な構文である void h(auto......); は、パラメータパックに ellipsis を付けた形です。
非推奨化後の推奨される C 互換形式は次のとおりです。
void f(int, ...);void g(auto args, ...);template<class T> void h(T, ...);
開発者はレガシーヘッダーをこれらの形式に更新し、コンパイラ警告を回避し、コードを将来にわたって安全に保つべきです。
本文
C++26は言語に小さくても意味のある整理をもたらします。具体的には、先頭にカンマが付いていないエリプシスパラメータ(
...)を非推奨とする変更です。この提案(P3176R1)は、C との互換性を高め、混乱を減らし、将来の言語機能への道を開くことを目的としています。
提案名は「オックスフォード・カンマ」にちょっとしたジョークが込められています。英語でリストの最後に置かれるカンマ(“and” の前)と同様に、関数パラメータ内のエリプシスの前にもカンマを必ず入れることを求めるものです。
問題点
まず用語を整理しましょう。ここで扱っているのは、
printf などで使われる C スタイルの可変長パラメータ(エリプシスパラメータ)です。テンプレートパックとは別物でありながら、両者とも ... を用います。
現在、C++ではエリプシスパラメータを宣言する方法が2つあります。
void foo(int, ...); // カンマ付き(C 互換) void foo(int...); // カンマなし(C++ 専用)
後者は標準化前の C++ の関数プロトタイプに由来し、以降も標準化された C++ に残っています。興味深いことに、C ではカンマを省略することが許されていません。C89 から変わらない規格は次のように定めています。
// C で有効なのはこの形だけ: int printf(char*, ...);
C++ は後に C 互換性のためカンマ付き形式を追加しましたが、旧構文も残しておくことで後方互換性を保っています。その結果
(int, ...) は両言語で有効ですが、(int...) は C++ のみで使用できます。
なぜ混乱するのか?
本当の混乱は C++11 で導入されたテンプレートパラメータパックに起因します。次の例を見てください。
template<class Ts> void f(Ts...); // 正しい:型 Ts のパラメータ + エリプシスパラメータ
多くの人は
(T...) をパラメータパックと結びつけがちですが、実際には Ts という単一パラメータに続いてエリプシスパラメータがある構造です。パラメータパックを宣言するには次のようにします。
template<class... Ts> void f(Ts... args); // args はパラメータパック
さらに、簡略化された関数テンプレートで混乱は増します。
// 簡易可変長関数テンプレート void g(auto... args); // 簡易非可変長関数テンプレート(エリプシスパラメータ付き) void g(auto args...);
二つの宣言は見た目が似ていますが、意味は全く異なります。後者は非推奨にするべきです。
6 ドットの奇妙なケース
現在の規則で許される最も奇妙な構文は次のようになります。
void h(auto......); // (auto..., ...) と同等
これは連続した 6 個のドットです(数え間違えていない限り)。関数テンプレートパラメータパックにエリプシスパラメータが続く形ですが、すべてのドットが
auto に適用されるように見えるため誤解を招きます。
非推奨になるもの
C++26 では先頭にカンマが付いていないエリプシスパラメータを非推奨とします。
// C++26で非推奨: void f(int...); void g(auto args...); template<class T> void h(T...); // T はパラメータパックではない // 推奨(C 互換): void f(int, ...); void g(auto args, ...); template<class T> void h(T, ...);
独立したエリプシスパラメータは有効なままです。
void f(...); // 有効、C 互換、曖昧さなし
影響
これは純粋に非推奨(削除は以前から拒否されていた)であり、既存コードが不正になることはありません。非推奨の使用箇所はカンマを追加するだけで機械的に変換できます。この変換はツールによって自動化しやすい単純なものです。
影響を受けるコード量は正確には不明ですが、著者は GitHub の検索で
T...... パターンが数十件見つかったと報告しています。実際に該当する宣言の数は無視できないほどであり、(T...) がエリプシスパラメータかテンプレートパックかを判定するにはセマンティック解析が必要です。
この非推奨は将来の言語機能への道を開きます。すでに
(int...) は P1219R2「同質可変長関数パラメータ」などの提案を妨げていました。このカンマなし形式を非推奨とすることで、委員会は将来の進化のためのデザインスペースを確保しつつ、C との一貫性を高め、混乱を減らしています。
結論
オックスフォード可変カンマは小さな変更ですが、多くのメリットがあります。C 互換性の向上、パラメータパックとの混同の削減、そして将来機能への設計余地の確保です。タイトルは遊び心があるものの、その動機は真剣であり、現代 C++ にほとんど役目を果たさない歴史的アーティファクトを整理することにあります。
エリプシスパラメータを使用しているなら、
... の前に必ずカンマを入れるようにしましょう。そうすればコードはより C 互換になり、混乱が減り、次の機能に備えることができます。