12904


関数において整数定数テンプレートを付加した際に発生するいくつかの構文エラーについて２つ質問です.

**①operator()の整数定数テンプレートの明示の際のシンタックスエラー**

[code]

    #include<iostream>
    struct object{
        template<std::size_t index>
        void operator()(){ std::cout << index << std::endl;}
    }
    
    int main(){
        object obj;
        obj<1>(); //ill-formed （obj < 1）のoperator<未定義エラー
        obj.operator()<1>(); //ok
    }
    
[/code]

なぜか obj<1>(); において, obj<1 が先に評価され,
整数とobjectの比較と判断されてしまうエラーがあります,これは規格どおりなのでしょうか,それともバグでしょうか.  
ちなみにobj.operator()<1>(); は動きます.

**②整数定数テンプレートメンバ関数において, 可変長引数テンプレートが正常に扱えない**

[code]

    #include<iostream>
    
    struct X{
        template<size_t t>
        void f(int a){
            std::cout << t << a << std::endl;   
        }
    };
    
    template <class S,typename ...Params>
    void f(S&& s,Params&&... params)
    {
        s.f<10>(std::forward<Params>(params)...); // error: expected ')' , expression contains unexpanded parameter packs 'Params'
      and 'params'
    
        s.f<10>(std::forward<Params...>(params...)); // error: reference to non-static member function must be called
    
        s.f<10>(params...); // error: expected ')'
    }
    
    int main(){
        f(X(),4);
        return 0;
    }
    
[/code]

**  
②.1 本来なら構文的に合っているunpack演算子が無効, または全然関係のないところでexpected')'  
②.2 意味のわからないnon-static function callエラー  
③.3 全然関係のないところで expected')'  
**

以上です.  
コンパイラのバグか, 仕様書どおりか, もしくは自分の構文ミスなのか全く判別がつきません.  
知識人の方, 一つでも心当たりがあれば是非お願いいたします.

よろしくお願いします.

環境(gcc及びLLVM)


CC BY-SA 3.0
2015-07-31T13:36:00.067
12890
2015-08-01T03:05:33.563
2015-07-31T15:42:01.273
10747
10747
question
c++ c++11
【C++11】メンバ関数で整数定数テンプレートを使用した際のエラー


両者共にtemplate限定子が必要だと思われます．

まず②は以下のように修正できます．

[code]

    #include <iostream>
    #include <utility>
    
    struct X{
        template<size_t t>
        void f(int a){
            std::cout << t << a << std::endl;
        }
    };
    
    template <typename S, typename... Params>
    void f(S&& s,Params&&... params)
    {
        s.template f<10>(std::forward<Params>(params)...); // error: expected ')' , expression contains unexpanded parameter packs 'Params'
        s.template f<10>(std::forward<Params...>(params...)); // error: reference to non-static member function must be called
        s.template f<10>(params...); // error: expected ')'
    }
    
    int main(){
        f(X(),4);
        return 0;
    }
    
[/code]

ここで用いられる関数テンプレート`f`が定義された時点では，各テンプレート引数の具体的な型は決定されていません．よって，修正前の状態では`s.f<10>(...)`の`<`と`>`が比較演算子と解釈される可能性があります．そこで，`s.f()`がメンバ関数テンプレートであることを明示するためにtemplate限定子を用いるというわけです．

①の問題もソースのコメントを見る限り同じ問題のように思えますが，②と同様に使おうとすると結局`obj.operator()()`を明示するのと変わらないですね．簡潔な方法は私には分かりません…


CC BY-SA 3.0
2015-07-31T16:33:09.397
12892
2015-07-31T16:33:09.397
7179
12890
answer


> ①operator()の整数定数テンプレートの明示の際のシンタックスエラー

C++の言語仕様通りです。`<`がテンプレート引数リストの開始記号として解釈されるのは、その前にある`obj`がテンプレート名( _template-id_
)または`operator()`( _operator-function-id_ )のときだけです。（厳密にはC++11 14.2
[temp.names]/paragraph 3を参照）

`obj<1>()`は上記ケースに該当しないため、ここは「より小さい(less than)比較演算子」として解釈されます。

* * *

> ②整数定数テンプレートメンバ関数において, 可変長引数テンプレートが正常に扱えない

メンバテンプレート関数名`f`の前に、限定子としての`template`キーワード、いわゆる`template`限定子を付与すると解決します。（C++11
14.2 [temp.names]/paragraph 4参照）

[code]

    template <class S, typename ...Params>
    void f(S&& s, Params&&... params)
    {
        s.template f<10>(std::forward<Params>(params)...);
        s.template f<10>(std::forward<Params...>(params...));
        s.template f<10>(params...);
    }
    
[/code]

（本題からは外れますが、2番目`std::forward<Params...>(params...)`は2個以上の実引数を与えたとき、`std::forward<A1,
A2>(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++コンパイラの実装次第です。一般論としては、誤ったコードからプログラマの意図を汲み取るのは非常に困難です。このため、プログラマから見たら意味不明なエラーメッセージに見えることは良くあります。


CC BY-SA 3.0
2015-08-01T02:41:58.473
12904
2015-08-01T03:05:33.563
2015-08-01T03:05:33.563
49
49
12890
answer