在依赖模板名称之前使用 template 关键字

303*_*303 8 c++ dependent-name language-lawyer compiler-bug c++20

考虑到以下代码示例,我希望必须template在此处使用关键字来指导编译器将变量视为v模板。然而,MSVC 拒绝使用该template关键字,而 Clang 和 GCC 实际上需要它。在这种情况下,C++20 标准中的哪条具体规则强制或禁止使用关键字template

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{}));
Run Code Online (Sandbox Code Playgroud)

实例


来自 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 
Run Code Online (Sandbox Code Playgroud)

来自 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
        ]
Run Code Online (Sandbox Code Playgroud)

Jan*_*tke 5

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

至于依赖类型,包括decltype

一个类型是依赖的,如果它是:

  • 模板参数,
  • [...]
  • 用 表示decltype(expression),其中expression与类型相关。

- [温度相关类型] p7.10

此外,x是类型相关的,因为(参见[temp.dep.expr] p3.1)它是:

通过名称查找与使用依赖类型声明的一个或多个声明相关联

泛型 lambda 的参数auto使调用运算符成为函数模板,因此很自然地x与模板参数相关联,而模板参数是相关的。因此template对于 来说是必要的decltype(x)::template v<>。所有编译器都同意,这是正确的。

在声明中

return x.template v<>;
Run Code Online (Sandbox Code Playgroud)

x是类型相关的,因为它通过名称查找与泛型 lambda 调用运算符的隐式模板参数相关联。因此,template是必要的。


注意:除了标准语言之外,直观上这是必要的,因为如果不知道这是一个模板,x.v <则可能会被解释为x.v小于...” 。v这在[temp.names] p3中正式说明。

另请参阅:在哪里以及为什么必须放置“template”和“typename”关键字?

MSVC 编译器错误

MSVC 不允许这一事实.template v<>显然是一个错误。值得注意的是,MSVC 确实接受:

[](s x){ return x.template v<>; }(s{})
Run Code Online (Sandbox Code Playgroud)

但是,使用autonot 作为s参数类型会导致编译器错误。这根本没有意义,因为templatetypename是可选的,不必要地添加它们永远不会导致失败。


注意:我无法在Microsoft 开发人员社区中找到现有的错误报告,因此可能尚未报告此问题。您可能想要报告此错误。