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

Use of template keyword before dependent template name

提问人:303 提问时间:9/20/2023 最后编辑:Jan Schultke303 更新时间:9/21/2023 访问量:161

问:

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

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

现场示例


来自 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 

来自 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
        ]
c++ 语言-lawyer c++20 编译器-bug 依赖项名称

评论

0赞 QuentinUK 9/21/2023
替换为它们都起作用。因此,编译器在推断 auto 时遇到了麻烦。(auto x)(s x)
5赞 Jarod42 9/21/2023
我会说msvc是错误的。
3赞 YSC 9/21/2023
@QuentinUK在此上下文中,使 lambda 模板化。即使它们被 称为 ,它们的主体也必须对任何类型有效;编译器不得假定为 (除非对于不可观察对象,根据 as-if 规则)。autosxs
0赞 YSC 9/21/2023
尽管是非规范性的,但此示例表明这是正确的形式:.我试图理解 [basic.lookup.qual.general]/3 是如何回答的。.template v<>p->X<0>::f(); // error: A​::​X not found in ((p->X) < 0) > ​::​f()

答:

5赞 Jan Schultke 9/21/2023 #1

简而言之,并且是依赖性的,并且在所有情况下都是允许和必要的。存在 MSVC 编译器错误。xdecltype(x)template

C++ 标准措辞

至于依赖类型,包括:decltype

如果类型符合以下条件,则类型是依赖的:

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

- [临时类型] p7.10

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

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

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

在声明中

return x.template v<>;

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


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

Смотритетакже: 我必须在哪里以及为什么必须放置“模板”和“typename”关键字?

MSVC 编译器错误

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

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

但是,使用 instead 而不是作为参数类型会导致编译器错误。这完全没有意义,因为 和 是可选的,不必要地添加它们永远不会导致失败。autostemplatetypename


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

评论

0赞 YSC 9/21/2023
我已经尽可能多地阅读了有关依赖查找的信息,但找不到支持“因此,模板是必要的”的引用。我什至找不到涉及模棱两可主题的引述。template_name < template_parameter_list > ...( template_name < template_parameter_list ) > ...
0赞 Jan Schultke 9/21/2023
@YSC它就在这个答案中,尽管在注释中。请参见 eel.is/c++draft/temp.names#3。 是必需的,因为没有一个项目符号都得到满足,因此被解释为小于运算符。第一个项目符号指出,这将导致解析为模板参数列表的分隔符,这正是我们所需要的。如果它被解析为小于运算符,则程序的格式将不正确。template<template<
0赞 Jan Schultke 9/21/2023
另请注意,第二个项目符号不适用,因为名称查找找不到任何依赖成员查找的内容。不过,这都超出了这个答案的范围,老实说,我属于我在哪里以及为什么必须放置“模板”和“typename”关键字?
0赞 YSC 9/21/2023
I've completely missed this item , which is kind of scary. Many thanks./3
0赞 303 9/30/2023
It seems the bug is rather obvious, I'm not sure how it has slipped through the cracks all these years. I've reported the bug to Microsoft with the help of your investigative work.