プログラミング言語C++において可変長引数テンプレートパラメータパックをラムダ式でキャプチャする際、そのキャプチャ方式によってellipsis(...
)の前置/後置が異なることに注意。
template <typename... Ts> void func(Ts... xs) { // C++11以降: 簡易キャプチャ(simple-capture) [xs...] { // xsの各要素をコピーキャプチャ }; [&xs...] { // xsの各要素を参照キャプチャ }; // C++2a: 初期化キャプチャ(init-capture) [...xs = std::move(xs)] { // xsの各要素をムーブキャプチャ }; }
N4800(C++2a WD) 7.5.5.2 構文規則, p17より一部引用。
→ 2021-05-11追記:本記事の内容には直接影響しないが、C++20言語仕様では P2095R0 採択により下記引用と少し異なる文法定義となっている。初期化キャプチャ中における参照キャプチャのパック展開構文を[&...xs = init]
へ修正している。
lambda-capture :
capture-list
(snip)
capture-list :
capture
capture-list,
capture
capture :
simple-capture...
opt
...
opt init-capture
A simple-capture followed by an ellipsis is a pack expansion (12.6.3). An init-capture preceded by an ellipsis is a pack expansion that introduces an init-capture pack (12.6.3) whose declarative region is the lambda-expression's compound-statement. [Example:
template<class... Args> void f(Args... args) { auto lm = [&, args...] { return g(args...); }; lm(); auto lm2 = [...xs=std::move(args)] { return g(xs...); }; lm2(); }-- end example]
メモ:P0780R1時点では初期化キャプチャ(init-capture)も後置ellipsis方式だったが、最終的に前置ellipsisに変更されてC++2a言語仕様に採択された。“導入される名前直前にellipsisを記述” という既存構文との一貫性を重視したのこと。*1
関連URL
- P0780R2 Allow pack expansion in lambda init-capture
- ラムダ式の初期化キャプチャ - cpprefjp C++日本語リファレンス
- c++ - Lambda pack capture with ellipsis on both sides - what is the meaning? - Stack Overflow
*1:P0780R2: "Following Core and Evolution guidance, the ellipses for an init-capture pack have been moved from following the init-capture to preceding it. This is consistent with the existing practice of ... preceding the name that it introduces."