質問: 関数において整数定数テンプレートを付加した際に発生するいくつかの構文エラーについて2つ質問です. **1operator()の整数定数テンプレートの明示の際のシンタックスエラー** ``` #include struct object{ template void operator()(){ std::cout << index << std::endl;} } int main(){ object obj; obj<1>(); //ill-formed (obj < 1)のoperator<未定義エラー obj.operator()<1>(); //ok } ``` なぜか obj<1>(); において, obj<1 が先に評価され, 整数とobjectの比較と判断されてしまうエラーがあります,これは規格どおりなのでしょうか,それともバグでしょうか. ちなみにobj.operator()<1>(); は動きます. **2整数定数テンプレートメンバ関数において, 可変長引数テンプレートが正常に扱えない** ``` #include struct X{ template void f(int a){ std::cout << t << a << std::endl; } }; template void f(S&& s,Params&&... params) { s.f<10>(std::forward(params)...); // error: expected ')' , expression contains unexpanded parameter packs 'Params' and 'params' s.f<10>(std::forward(params...)); // error: reference to non-static member function must be called s.f<10>(params...); // error: expected ')' } int main(){ f(X(),4); return 0; } ``` **2.1 本来なら構文的に合っているunpack演算子が無効, または全然関係のないところでexpected')' 2.2 意味のわからないnon-static function callエラー 3.3 全然関係のないところで expected')'** 以上です. コンパイラのバグか, 仕様書どおりか, もしくは自分の構文ミスなのか全く判別がつきません. 知識人の方, 一つでも心当たりがあれば是非お願いいたします. よろしくお願いします. 環境(gcc及びLLVM)
回答: > > 1operator()の整数定数テンプレートの明示の際のシンタックスエラー > > > C++の言語仕様通りです。`<`がテンプレート引数リストの開始記号として解釈されるのは、その前にある`obj`がテンプレート名(*template-id*)または`operator()`(*operator-function-id*)のときだけです。(厳密にはC++11 14.2 [temp.names]/paragraph 3を参照) `obj<1>()`は上記ケースに該当しないため、ここは「より小さい(less than)比較演算子」として解釈されます。 > > 2整数定数テンプレートメンバ関数において, 可変長引数テンプレートが正常に扱えない > > > メンバテンプレート関数名`f`の前に、限定子としての`template`キーワード、いわゆる`template`限定子を付与すると解決します。(C++11 14.2 [temp.names]/paragraph 4参照) ``` template void f(S&& s, Params&&... params) { s.template f<10>(std::forward(params)...); s.template f<10>(std::forward(params...)); s.template f<10>(params...); } ``` (本題からは外れますが、2番目`std::forward(params...)`は2個以上の実引数を与えたとき、`std::forward(a1, a2)`のように展開されてしまい実用性がありません。) > > 1 本来なら構文的に合っているunpack演算子が無効, または全然関係のないところでexpected')' > > 2 意味のわからないnon-static function callエラー > > 3 全然関係のないところで expected')' > > > いずれのエラーメッセージも、トークン`<`が「less than比較演算子」として解釈された結果だと考えられます。`s.f<10>(ARGS);` は `( (s.f < 10) > ( ARGS ) ) ;` という構文に解釈されています。つまり、メンバ`s.f`と値`10`を比較`<`し、その結果と`(ARGS)`評価結果を比較`>`し、最終結果は捨てるという式文です。 また部分式`(ARGS)`は、パラメータパック展開の適用対象外です。(C++11 14.5.3 [temp.variadic]/paragraph 4参照) (ちなみに、エラーメッセージ中の"expression contains unexpanded parameter packs 'Params' and 'params'"が、辛うじて上記の解釈を示唆しています。) この解釈ではいずれも文法的に不正となるため、どのようなエラーメッセージを出力するかはC++コンパイラの実装次第です。一般論としては、誤ったコードからプログラマの意図を汲み取るのは非常に困難です。このため、プログラマから見たら意味不明なエラーメッセージに見えることは良くあります。