可以捕获的实体的声明:它应该产生lambda之外的实体的类型吗?

发布于 2025-01-29 15:51:34 字数 1652 浏览 1 评论 0 原文

考虑以下简单的独立代码:

template<typename T>
void foo();

void bar() {
    int i;
    auto l = [&i]() -> decltype(auto) {
        decltype(auto) x = i;
        foo<decltype(x)>();
        foo<decltype(i)>();
        return static_cast<decltype(i)>(i);
    };
    l();
    foo<decltype(l())>();
}

GCC生成以下内容:

bar():
        sub     rsp, 8
        call    void foo<int&>()
        call    void foo<int>()
        add     rsp, 8
        jmp     void foo<int>()

Clang生成以下内容:

bar():                                # @bar()
        push    rax
        call    void foo<int>()
        call    void foo<int>()
        pop     rax
        jmp     void foo<int>()                     # TAILCALL

MSVC生成以下内容:

void bar(void) PROC                                        ; bar, COMDAT
$LN8:
        sub     rsp, 40                             ; 00000028H
        call    void foo<int &>(void)                  ; foo<int &>
        call    void foo<int &>(void)                  ; foo<int &>
        add     rsp, 40                             ; 00000028H
        jmp     void foo<int &>(void)                        ; foo<int &>
void bar(void) ENDP   

 

似乎所有三个编译器都不同意。哪一个是正确的,C ++标准的哪一部分证实了这一点?

在我看来, exltype(i)应始终是 int ,并且永远不要 int&amp; ,无论是否被捕获。

义务编译器Explorer链接

Consider this simple self-contained code:

template<typename T>
void foo();

void bar() {
    int i;
    auto l = [&i]() -> decltype(auto) {
        decltype(auto) x = i;
        foo<decltype(x)>();
        foo<decltype(i)>();
        return static_cast<decltype(i)>(i);
    };
    l();
    foo<decltype(l())>();
}

GCC Generates the following:

bar():
        sub     rsp, 8
        call    void foo<int&>()
        call    void foo<int>()
        add     rsp, 8
        jmp     void foo<int>()

Clang Generates the following:

bar():                                # @bar()
        push    rax
        call    void foo<int>()
        call    void foo<int>()
        pop     rax
        jmp     void foo<int>()                     # TAILCALL

MSVC Generates the following:

void bar(void) PROC                                        ; bar, COMDAT
$LN8:
        sub     rsp, 40                             ; 00000028H
        call    void foo<int &>(void)                  ; foo<int &>
        call    void foo<int &>(void)                  ; foo<int &>
        add     rsp, 40                             ; 00000028H
        jmp     void foo<int &>(void)                        ; foo<int &>
void bar(void) ENDP   

 

It seems all three compiler disagree. Which one is right and what part of the C++ standard confirms it?

In my mind, decltype(i) should always be int, and never int&, no matter if it is captured or not.

Obligatory compiler explorer link

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不奢求什么 2025-02-05 15:51:34

exltype(auto) [dcl.type.auto.deduct]/4

如果占位符 - 型特定器 是形式 type-constraint opt ecltype(auto) t 应独自成为占位符。按照 [dcl.type.decltype] ,好像 e exltype 。。

的操作数

这意味着 code> nectType(auto)x = i 等效于 exltype(i)x = i 。关于 decltype(i)说明:

  • 否则,如果 e 是无父母, id-xexpression 或无父母的类成员访问( [expr.ref] ), exltype(e) e 命名的实体的类型。如果没有这样的实体,则该程序是不形成的;

因此, exltype(i) i 命名的实体类型,即, int 。因此, x 是类型 int 的类型,因此, exltype(x)也是 int 。因此,在这种情况下,Clang是正确的。 GCC中的此错误已针对GCC 14( patrick )。


但是,似乎此修复会导致海湾合作委员会的另一个错误。如果我们将 i 的类型更改为 int&amp; ,则以下代码演示了此问题( godbolt ):

template <typename T> void foo();
void bar(int &i) {
  auto l = [&i]() -> decltype(auto) {
    decltype(auto) x = i;
    foo<decltype(x)>(); // [Clang] int& [GCC 14] int  [GCC 13] int&
    foo<decltype(i)>(); // [Clang] int& [GCC 14] int& [GCC 13] int&
    return i;
  };
  l();
  foo<decltype(l())>(); // [Clang] int& [GCC 14] int  [GCC 13] int&
}

遵循与上述相同的推理,在这种情况下,Clang和GCC 13是正确的。

decltype(auto) is specified in [dcl.type.auto.deduct]/4:

If the placeholder-type-specifier is of the form type-constraintopt decltype(auto), T shall be the placeholder alone. The type deduced for T is determined as described in [dcl.type.decltype], as though E had been the operand of the decltype.

This means decltype(auto) x = i is equivalent to decltype(i) x = i. Regarding decltype(i), [dcl.type.decltype]/1.3 states:

  • otherwise, if E is an unparenthesized id-expression or an unparenthesized class member access ([expr.ref]), decltype(E) is the type of the entity named by E. If there is no such entity, the program is ill-formed;

Thus, decltype(i) is the type of entity named by i, i.e., int. Therefore, x is of type int, and consequently, decltype(x) is also int. Hence, Clang is correct in this case. This bug in GCC has been fixed for GCC 14 (Patrick).


However, it appears that this fix causes another bug in GCC. If we change the type of i to int&, the following code demonstrates this issue (Godbolt):

template <typename T> void foo();
void bar(int &i) {
  auto l = [&i]() -> decltype(auto) {
    decltype(auto) x = i;
    foo<decltype(x)>(); // [Clang] int& [GCC 14] int  [GCC 13] int&
    foo<decltype(i)>(); // [Clang] int& [GCC 14] int& [GCC 13] int&
    return i;
  };
  l();
  foo<decltype(l())>(); // [Clang] int& [GCC 14] int  [GCC 13] int&
}

Following the same reasoning as above, Clang and GCC 13 are correct in this case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文