C++14で導入されるジェネリックラムダ(generic lambda)、可変長引数テンプレート(variadic template parameter)、ellipsis(...
)の組み合わせによる文法上の曖昧さについて。gccとClangのバグ。
struct { template<typename...Args> auto operator()(Args&&...) const { } } f1; auto f2 = [](auto&&...) { }; int main() { f1(); f2(); // ??? }
gcc 4.9.1(-std=c++1y), Clang 3.5.0(-std=c++14)では、ジェネリックラムダ式の(auto&&...)
を(auto&&, ...)
と誤って解釈し(→id:yohhoy:20130407)、それぞれ下記の通りコンパイルエラーとなる(エラーメッセージ抜粋)。*1
error: no match for call to '(
) ()'
note: candidate is:
note: template
note: template argument deduction/substitution failed:
note: candidate expects 1 argument, 0 provided
error: no matching function for call to object of type '(lambda at source.cpp:6:11)'
note: candidate function template not viable: requires at least 1 argument, but 0 were provided
なお、ジェネリックラムダ式で関数パラメータパック(function parameter pack)の名前(下記コードではargs
)を明示すれば、gcc, Clangともに期待通りコンパイルされる。
auto f3 = [](auto&&... args) { }; f3(); // OK
N3937(C++14 DIS) 8.3.5/15より引用(下線部は強調)。
15 There is a syntactic ambiguity when an ellipsis occurs at the end of a parameter-declaration-clause without a preceding comma. In this case, the ellipsis is parsed as part of the abstract-declarator if the type of the parameter either names a template parameter pack that has not been expanded or contains
auto
; otherwise, it is parsed as part of the parameter-declaration-clause.102
脚注102) One can explicitly disambiguate the parse either by introducing a comma (so the ellipsis will be parsed as part of the parameter-declaration-clause) or by introducing a name for the parameter (so the ellipsis will be parsed as part of the declarator-id).
ノート:関数/ラムダ式の仮引数宣言周りの定義は分かりづらいが、ellipsisをparameter-declaration-clauseの一部として解釈=Cスタイルの可変引数リスト、ellipsisをdeclarator-idの一部として解釈=C++可変長引数テンプレートの関数パラメータパック となる。(C++11 8.3.5/p13)
関連URL