5

Knowing Where and why do we have to put the template and typename keywords, I was surprised to learn that MSVC accepts the following code:

struct foo {
    using bar = int;
};

template <typename T>
void quux() {
    T::template bar b;
}

int main() {
    quux<foo>();
}

From my understanding, the usage of T::template bar b; is incorrect. The correct way to declare b would be to use typename, like so: typename T::bar b; (instead of T::template bar b;). template would imply that bar is a, well, a template, which is not the case.

Is it a bug in MSVC resulting in it accepting incorrect code, or is it permitted by the standard and simply both Clang and GCC don't implement it that way (thus requiring the proper usage of typename here)?

Fureeish
  • 12,533
  • 4
  • 32
  • 62
  • CTAD comes to mind. But `T` is dependent, [which is a no-no](https://timsong-cpp.github.io/cppwp/n4868/dcl.type.simple#2.sentence-3). So I think the `template` keyword can't serve any purpose. – StoryTeller - Unslander Monica Aug 16 '21 at 17:12
  • MSVC handles templates a bit like macros. It does not try to parse them before instantiation. Therefore, unlike the linked question, it does *not* need `template` nor `typename` keywords that are normally mandatory by C++ Standard. My guess is that therefore, it completely ignores `template` and `typename` keywords in dependent name contexts, and does not notice when they are used incorrectly. – prapin Aug 16 '21 at 18:17
  • @prapin not quite the case - either `template` or `typename` is still required if the dependent name is used in a different file (e.g., if `foo` would've been `#include`d), although in some cases the other one is necessary. – Fureeish Aug 16 '21 at 19:19
  • 1
    @Fureeish: That sounds a bit unbelievable, considering that MSVC turns cpp files with their #incldues into Translation Units just like any other compiler. See the output using `/E` – MSalters Aug 16 '21 at 20:56
  • 2
    @prapin that's the old behavior. In newer versions it has switched to standard-compliant two-phase name lookup instead of token pasting for templates, which can be turned off with [`/Zc:twoPhase-`](https://learn.microsoft.com/en-us/cpp/build/reference/zc-twophase?view=msvc-160). See also [C++ Conformance improvements, behavior changes, and bug fixes in Visual Studio 2019](https://learn.microsoft.com/en-us/cpp/overview/cpp-conformance-improvements?view=msvc-160) – phuclv Aug 17 '21 at 00:47

1 Answers1

1

MSVC has a long-standing bug - it was already an old bug when I asked that template-typename question which you linked. In short, C++ since 1998 requires Two-Phase Name Lookup in templates. In the first phase, when the template itself is compiled, only the names which are not dependent are looked up, as the actual template arguments are not yet known. In the second phase, dependent names are looked up (for details, see the linked question).

But MSVC doesn't do this, and does all lookup when instantiating the template. In your case, that means all the lookup is done when MSVC compiles quux<foo>, and nothing when compiling quux<T>. And since it doesn't do the first phase, it doesn't need that typename on a dependent name. MSVC already knows about quux::b.

It appears that MSVC goes a bit further. Not only does it ignore the correct typename, but it also ignores incorrect use of template as in this example. That's not entirely surprising when ignoring things.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • 3
    it's been fixed in VS2019 [C++ Conformance improvements, behavior changes, and bug fixes in Visual Studio 2019](https://learn.microsoft.com/en-us/cpp/overview/cpp-conformance-improvements?view=msvc-160). You need `/Zc:twoPhase-` for the old behavior – phuclv Aug 17 '21 at 00:49