Search code examples
c++language-lawyerc++20compiler-bugdependent-name

Use of template keyword before dependent template name


Considering the following code example, I would expect to have to use the template keyword here to guide the compiler to treat variable v as a template. However, MSVC rejects the use of the template keyword, whereas Clang and GCC actually require it. Which specific rule in the C++20 standard either mandates or forbids the use of the template keyword in this case?

struct s {
    template<typename...>
    static constexpr auto v = true;
};
// all ok
static_assert([](auto x){ return decltype(x)::template v<>; }(s{}));
// clang ok, gcc ok, msvc nope
static_assert([](auto x){ return x.template v<>; }(s{}));
// clang nope, gcc nope, msvc ok
static_assert([](auto x){ return x.v<>; }(s{}));

Live example


The error message from Clang:

<source>:10:36: error: use 'template' keyword to treat 'v'
as a dependent template name
   10 | static_assert([](auto x){ return x.v<>; }(s{}));
      |                                    ^
      |                                    template 

The error message from MSVC:

<source>(8): error C2187: syntax error: 'template' was unexpected here
<source>(8): note: see reference to function template instantiation
'auto <lambda_2>::operator ()<s>(_T1) const' being compiled
        with
        [
            _T1=s
        ]

Solution

  • In short, x and decltype(x) are dependent, and template is allowed and necessary in all cases. There is an MSVC compiler bug.

    C++ standard wording

    As for dependent types, including decltype:

    A type is dependent if it is:

    • a template parameter,
    • [...]
    • denoted by decltype(expression), where expression is type-dependent.

    - [temp.dep.type] p7.10

    Furthermore, x is type-dependent because (see [temp.dep.expr] p3.1) it is:

    associated by name lookup with one or more declarations declared with a dependent type

    The auto parameter for the generic lambda makes the call operator a function template, so naturally, x is associated with a template parameter, which is dependent. Therefore template is necessary for decltype(x)::template v<>. All compilers agree and this is correct.

    In the statement

    return x.template v<>;
    

    x is type-dependent because it is associated by name lookup with an implicit template parameter of the generic lambda's call operator. Therefore, template is necessary.


    Note: Besides the standardese, it's intuitively necessary because x.v < could be interpreted as "x.v is less than ..." if it isn't known that v is a template. This is formally stated in [temp.names] p3.

    See also: Where and why do I have to put the "template" and "typename" keywords?

    MSVC compiler bug

    The fact that MSVC doesn't allow .template v<> is obviously a bug. It's worth noting that MSVC does accept:

    [](s x){ return x.template v<>; }(s{})
    

    However, using auto instead of s as the parameter type leads to a compiler error. This makes no sense at all, since template and typename are optional and adding them unnecessarily should never cause failure.


    Note: I was unable to find an existing bug report in the Microsoft Developer Community, so maybe this hasn't been reported yet. You may want to report this bug.