yohhoyの日記

技術的メモをしていきたい日記

Last Piece of ラムダ式への属性指定

C++20現在の言語仕様では、ラムダ式に対して(普通のプログラマが期待するであろう)属性指定は行えない。C++2b(C++23)に向けた提案(PDF)P2173R0が進行中。
2022-02-17追記:2022年2月会合にてC++2b(C++23)へ提案文書(PDF)P2173R1採択された。

下記コードはC++構文規則上は許容されるものの、ラムダ式戻り値に対するnodiscard属性指定ではなく、ラムダ式により生成されるクロージャクラスClosureの関数呼び出し演算子オーバーロード関数型int Closure::operator()() constに対する属性指定と解釈される。

// C++20: ラムダ戻り値にnodiscard属性を指定 ??
auto lm = [] () [[nodiscard]] { return 42; };
// GCC 11.0/-std=c++2a
//  warning: 'nodiscard' attribute can only be applied to functions or to class or enumeration types
// Clang 11.1/-std=c++2a
//  error: 'nodiscard' attribute cannot be applied to types

C++2bにおけるラムダ式戻り値に対する属性指定は、パラメータ宣言部の直前に記述する構文となる予定。C++11~C++20現在の関数型に対する属性指定*1はそのまま維持される。

// C++2b: ラムダ戻り値にnodiscard属性を指定
auto lm = [] [[nodiscard]] () { return 42; };
//           ^^^^^^^^^^^^^

std::integral auto f = /*...*/;
// C++2b: ジェネリックラムダ戻り値にnodiscard属性を指定
auto glm = [f] <typename T> requires std::integral<T>
    [[nodiscard]] (T n) mutable noexcept -> T { return n * f++; };
//  ^^^^^^^^^^^^^

おまけ:GCC 9.3以降では上記C++2b構文が期待通りに解釈される(言語バージョン指定-std=c++NNは不問)。GCC Bugzilla 90333 によれば意図的な仕様拡張か?Clang 13ではC++2b以降の仕様である旨が表示される*2

関連URL

*1:もし本当に必要ならば、構文的にはnoexcept指定(exception-specification)の直後、戻り値型後置(trailing-return-type)の直前に属性指定を記述する。

*2:"warning: an attribute specifier sequence in this position is a C++2b extension [-Wc++2b-extensions]"