Search code examples
c++templateslanguage-lawyerdependent-name

C++ - Why is the 'template' keyword required here?


I have the following code:

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;
}

When building this with both gcc 9.2 and clang (9.0), I'm getting a compilation error due to the template keyword being required for invoking fun. Clang shows:

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

I don't understand why the compiler thinks fun is a dependent name in the context of f, since f is not a template itself. If I change C to be a regular class instead of a template, the error goes away; however, I don't see why there should be an error in the first place since neither S nor f depend on TC.

Oddly enough, MSVC 19.22 compiles this just fine.


note

Before voting to close as dupe of Where and why do I have to put the "template" and "typename" keywords? please consider this is a special case where even if S is indeed a dependent name, in the context of f it would not be dependent if not for the fact that they are members of the current instantiation.


Solution

  • Consider:

    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) is parsed as an expression containing of two comparison operations < and >, and this is fine for #1 but fails for #2.

    If this is changed to s.template a<0>(i) then #2 is OK and #1 fails. Thus the template keyword is never redundant here.

    MSVC is capable of interpreting the expression s.a<0>(i) both ways within the same program. But this is not correct according to the Standard; each expression should have only one parse for the compiler to deal with.