C++ で次のコードが問題なくコンパイルされます。
#include <print>
int main() {
[/**/[,,,,]/**/]
[
[
,,,, ,,,,
,,,, ,,,,
,,,,
,,,,,,,,
,,,,,,,,
,, ,,
]
]
std::println("Hello, World!");
}
なんだこれ????
属性の構文規則
[ [ と ] ] で囲まれているものは「属性 (attributes)」といって、なんかいろんなところに書けます。
その構文規則を見てみます。
attribute-specifier-seq:
https://eel.is/c++draft/dcl.attr#grammar-1 より抜粋- attribute-specifier attribute-specifier-seqopt
attribute-specifier:[[attribute-using-prefixopt attribute-list]][[annotation-list]]- alignment-specifier
attribute-list:- attributeopt
- attribute-list
,attributeopt- attribute
...- attribute-list
,attribute...
[[ は2つのトークン
1つ目の注目ポイントは [ と [ が離れていることです。
実は C++ に [[ というトークンはなく、 [[ は2つのトークンとして扱われます。
]] も同様です。
ということは、その間に空白文字やコメントを入れたり、1つだけダイグラフに変えたりしても問題ないということです!
[ /* ほげほげ */
[deprecated("こんな書き方するなし")] \
:>
void hoge();
, は好きなだけ設置可能
属性のカッコの中には attribute-list を書くことができます。
2つ目の注目ポイントは attribute-list の導出規則に登場するカンマです。
attribute-list:
- attributeopt
- attribute-list
,attributeopt- attribute
...- attribute-list
,attribute...
attribute-list の2つ目の導出規則により、 attribute-list 末尾にカンマを追加できます。
Trailing comma というやつですね。
[[
deprecated,
maybe_unused,
nodiscard,
]]
int fuga();
この2つ目の導出規則は何回でも適用できます。
つまり、このカンマは好きなだけ追加することができます。(?)
[[
deprecated,,,,,,,,
maybe_unused,,,,,,,,
nodiscard,,,,,,,,
]]
int fuga();
attribute-list の1つ目の導出規則により、 attribute-list は空にできます。
つまり、カンマの前に何も書かなくても許容されます。(???)
[[
,,,,,,,,
,,,,,,,,
,,,,,,,,
]]
int fuga();
[/**/[,,,,]/**/]
結論、 [/**/[,,,,]/**/] ←これは、ただの空の属性です。
おわり