C ++-ここで「テンプレート」キーワードが必要なのはなぜですか?


9

私は次のコードを持っています:

template <typename TC>
class C
{
    struct S
    {
        template <typename TS>
        void fun() const
        {}
    };

    void f(const S& s)
    {
        s.fun<int>();
    }
};

// Dummy main function
int main()
{
    return 0;
}

これをgcc 9.2とclang(9.0)の両方でビルドすると、templateを呼び出すために必要なキーワードが原因で、コンパイルエラーが発生しますfun。Clangのショー:

error: use 'template' keyword to treat 'fun' as a dependent template name
        s.fun<int>();
          ^
          template 

コンパイラは考えて、なぜ私は理解していないfunのコンテキストで依存名であるfことから、fテンプレート自体ではありません。Cテンプレートではなく通常のクラスに変更すると、エラーはなくなります。ただし、に依存していSないfため、そもそもなぜエラーが発生するのかわかりませんTC

奇妙なことに、MSVC 19.22はこれを適切にコンパイルします。


注意

投票する前に、どこに、そしてなぜ「テンプレート」と「タイプ名」のキーワードを置かなければならないのか?これがS実際に依存名である場合でもf、それらが現在のインスタンス化のメンバーであるという事実に関係なく依存しないという特別なケースであると考えてください。


コメントは詳細な議論のためのものではありません。この会話はチャットに移動さました
Bhargav Rao

回答:


10

考慮してください

template<typename T>
struct C
{
    struct S
    {
        int a = 99;
    };

    void f(S s, int i)
    {
        s.a<0>(i);
    }
};

template<>
struct C<long>::S
{
    template<int>
    void a(int)
    {}
};

int main()
{
    C<int>{}.f({}, 0); // #1
    C<long>{}.f({}, 0); // #2
}

s.a<0>(i)は、2つの比較演算<and を含む式として解析され>ます。これは#1では問題ありませんが、#2では失敗します。

これをに変更するとs.template a<0>(i)、#2は問題なく、#1は失敗します。したがって、templateキーワードがここで冗長になることはありません。

MSVCは、同じプログラム内で双方向で式を解釈できs.a<0>(i)ます。しかし、これは規格によると正しくありません。各式は、コンパイラーが処理する1つの解析のみを持つ必要があります。


私はまだこれを完全に理解していません。あなたの例は、このケースでは、Cまたはのいずれかの特殊化を使用することを示していますが、両方をインスタンス化することはできません。ここでtemplateキーワードはIMHOですが、SどれCがインスタンス化されるかによって選択されるためです。templateキーワードがなければ、両方をインスタンス化することができ、fの動作はインスタンスごとに異なります。
マーティン

2
@Martin要点は、各トークンはソースファイルで構文上の役割を1つだけ持つべきであるということです。たとえば、トークン<が1つのテンプレートのインスタンス化で比較演算子になり、別のインスタンス化で開き山かっこになるのは問題です。これは、コンパイラがテンプレートをASTに解析できるようにするためです(テンプレートタイプのプレースホルダを使用)。
ecatmur

それは理にかなっている。ありがとう!
マーティン

7

funのテンプレートパラメータに応じて、テンプレート関数である場合とそうでない場合があります(またはまったく存在しない場合もあります)class C

これは、S(を特化せずにC)特化できるためです。

template <> struct C<int>::S {};

コンパイラーfunは、最初にclass C(テンプレートパラメーターを置き換える前に)見たときにテンプレートであるかどうかを知りたいので、template必須です。


1
心...吹き飛ばされる...
bolov

これに対するフォローアップは、のこれらの新しい定義にSがアクセスできるかどうかfです。表示できない場合は、fとにかく表示できないため、この制限を設定しても意味がありません。
マーティン

@Martin GCC、Clang、MSVCの両方でf検出されます。
HolyBlackCat

@bolovええ、さまざまなことに特化できます
HolyBlackCat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.