この正確な例は、C99標準ドラフト(C11と同じ詳細)のセクション6.4字句要素の段落4で説明されています。
入力ストリームが特定の文字までの前処理トークンに解析されている場合、次の前処理トークンは、前処理トークンを構成する可能性のある最も長い文字シーケンスです。[...]
これは、曖昧さを回避するために字句解析で使用され、有効なトークンを形成するためにできるだけ多くの要素を使用することによって機能する最大ムンチルールとも呼ばれます。
段落には2つの例もあり、2番目の例は質問と完全に一致し、次のようになります。
例2プログラムフラグメントx +++++ yはx ++ ++ + yとして解析されます。これは、解析x ++ + ++ yが正しい式を生成する場合でも、インクリメント演算子の制約に違反します。
それは私たちにそれを伝えます:
a+++++b
次のように解析されます:
a ++ ++ + b
最初のポストインクリメントの結果は右辺値であり、ポストインクリメントには左辺値が必要であるため、ポストインクリメントの制約に違反します。これは、6.5.2.4
Postfixインクリメントおよびデクリメント演算子のセクションで説明されています(強調は私のものです):
後置インクリメントまたはデクリメント演算子のオペランドは、修飾型または非修飾の実数型またはポインタ型であり、変更可能な左辺値でなければなりません。
そして
後置++演算子の結果は、オペランドの値です。
C ++ Gotchasの本でも、Gotcha #17
Maximum Munch Problemsでこのケースが取り上げられており、C ++でも同じ問題であり、いくつかの例も示されています。これは、次の文字セットを処理するときに説明されます。
->*
字句アナライザは、次の3つのことの1つを実行できます。
- 3つのトークンとして扱い:
-
、>
および*
- 2つのトークンとして扱い:
->
と*
- それを1つのトークンとして扱います。
->*
最大ムンクのルールは、これらのあいまいさを避けることができます。著者はそれを指摘しています(C ++のコンテキストでは):
それが原因よりもはるかに多くの問題を解決しますが、2つの一般的な状況では、それは厄介です。
最初の例は、テンプレート引数もテンプレートであるテンプレートです(C ++ 11で解決されました)。次に例を示します。
list<vector<string>> lovos; // error!
^^
これは、閉じ山カッコをシフト演算子として解釈するため、明確にするためにスペースが必要です。
list< vector<string> > lovos;
^
2番目のケースは、ポインタのデフォルト引数を含みます。次に例を示します。
void process( const char *= 0 ); // error!
^^
解釈される*=
代入演算子、この場合の解決策は、宣言内のパラメータの名前を指定することです。