一行函数模板c+的内联性保证+; 在C++标准库中,有许多线性函数模板。例如,std::move本质上只是一个cast,一个实现可能是: template<typename _Tp> constexpr typename std::remove_reference<_Tp>::type&& move(_Tp&& __t) noexcept { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); } 模板 constexpr typename std::remove_reference::type&& 移动(&&t)不例外 {return static_cast(__t);}

一行函数模板c+的内联性保证+; 在C++标准库中,有许多线性函数模板。例如,std::move本质上只是一个cast,一个实现可能是: template<typename _Tp> constexpr typename std::remove_reference<_Tp>::type&& move(_Tp&& __t) noexcept { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); } 模板 constexpr typename std::remove_reference::type&& 移动(&&t)不例外 {return static_cast(__t);},c++,C++,我知道实际上,std::move不会生成任何机器代码,因为它只是一个强制转换。我的问题是:标准中是否有任何保证说,对于像std::move或std::forward这样的函数(只做强制转换),它们必须始终是内联的(因此不会生成机器代码)?换句话说,(学究式)编译器是否可以将它们视为普通函数(即,将参数放在堆栈上,并生成call和ret指令)?这不是标准,而是Scott Meyer的有效CPP。 第30项:了解内联的细节。 编译器优化是非常重要的 通常设计用于缺少函数调用的代码扩展,因此 内联函数

我知道实际上,std::move不会生成任何机器代码,因为它只是一个强制转换。我的问题是:标准中是否有任何保证说,对于像std::move或std::forward这样的函数(只做强制转换),它们必须始终是内联的(因此不会生成机器代码)?换句话说,(学究式)编译器是否可以将它们视为普通函数(即,将参数放在堆栈上,并生成call和ret指令)?

这不是标准,而是Scott Meyer的有效CPP。
第30项:了解内联的细节。

编译器优化是非常重要的 通常设计用于缺少函数调用的代码扩展,因此 内联函数时,可以启用编译器执行上下文- 函数体上的特定优化。大多数编译器 切勿对“概述”的函数调用执行此类优化。

在内存有限的机器上,过于热心 内联可能会导致程序对于可用程序来说太大 空间即使使用虚拟内存,内联引起的代码膨胀也会导致 为了增加分页,降低了指令缓存命中率,并且 伴随这些事件的绩效惩罚。

另一方面,如果内联函数体非常短,则代码 为函数体生成的代码可能小于生成的代码 用于函数调用。如果是这样的话,内联函数可能会 实际上会导致更小的目标代码和更高的指令缓存命中率 速度

请记住,内联是对编译器的请求,而不是命令。 …
模板实例化独立于内联。如果你在写一篇文章 模板,并且您相信从 模板应该内联,内联声明模板

但是,如果您正在为没有理由希望内联的函数编写模板,请避免将模板内联声明(显式或隐式)。内联 有成本,您不希望未经事先考虑就招致成本。

... 让我们完成观察,内联是一个请求 编译器可能会忽略这一点。大多数编译器拒绝内联函数 他们认为太复杂(例如,那些包含循环或是递归的), 除最简单的虚拟函数调用外,所有调用都不支持内联

所有这些加起来就是:给定的内联函数是否实际是 内联取决于您正在使用的构建环境-主要是 编译器。幸运的是,大多数编译器的诊断级别 如果未能内联函数,将导致警告 您已要求他们这样做。

有时编译器会为内联函数生成函数体 即使他们非常愿意内联函数。例如 如果程序采用内联函数的地址,编译器 通常必须为其生成一个概述的函数体


如果你能拿到这本书,读一读整本书,它会消除你的许多疑虑

这不是来自标准,而是来自Scott Meyer的有效CPP。
第30项:了解内联的细节。

编译器优化是非常重要的 通常设计用于缺少函数调用的代码扩展,因此 内联函数时,可以启用编译器执行上下文- 函数体上的特定优化。大多数编译器 切勿对“概述”的函数调用执行此类优化。

在内存有限的机器上,过于热心 内联可能会导致程序对于可用程序来说太大 空间即使使用虚拟内存,内联引起的代码膨胀也会导致 为了增加分页,降低了指令缓存命中率,并且 伴随这些事件的绩效惩罚。

另一方面,如果内联函数体非常短,则代码 为函数体生成的代码可能小于生成的代码 用于函数调用。如果是这样的话,内联函数可能会 实际上会导致更小的目标代码和更高的指令缓存命中率 速度

请记住,内联是对编译器的请求,而不是命令。 …
模板实例化独立于内联。如果你在写一篇文章 模板,并且您相信从 模板应该内联,内联声明模板

但是,如果您正在为没有理由希望内联的函数编写模板,请避免将模板内联声明(显式或隐式)。内联 有成本,您不希望未经事先考虑就招致成本。

... 让我们完成观察,内联是一个请求 编译器可能会忽略这一点。大多数编译器拒绝内联函数 他们认为太复杂(例如,那些包含循环或是递归的), 除最简单的虚拟函数调用外,所有调用都不支持内联

所有这些加起来就是:给定的内联函数是否实际是 内联取决于您正在使用的构建环境-主要是 编译器。幸运的是,大多数编译器的诊断级别 如果未能内联函数,将导致警告 您已要求他们这样做。

有时编译器会为内联函数生成函数体 即使他们是完美的wil
#include <utility>

struct Foo {
    int i;
    Foo(Foo &&other) :i(other.i) {};
};

Foo with_move(Foo f) {
    return std::move(f);
}
Foo::Foo(Foo&&):
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     QWORD PTR [rbp-16], rsi
        mov     rax, QWORD PTR [rbp-16]
        mov     edx, DWORD PTR [rax]
        mov     rax, QWORD PTR [rbp-8]
        mov     DWORD PTR [rax], edx
        nop
        pop     rbp
        ret
with_move(Foo):
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     QWORD PTR [rbp-8], rdi
        mov     QWORD PTR [rbp-16], rsi
        mov     rax, QWORD PTR [rbp-16]
        mov     rdi, rax
        call    std::remove_reference<Foo&>::type&& std::move<Foo&>(Foo&)
        mov     rdx, rax
        mov     rax, QWORD PTR [rbp-8]
        mov     rsi, rdx
        mov     rdi, rax
        call    Foo::Foo(Foo&&)
        mov     rax, QWORD PTR [rbp-8]
        leave
        ret
std::remove_reference<Foo&>::type&& std::move<Foo&>(Foo&):
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     rax, QWORD PTR [rbp-8]
        pop     rbp
        ret
with_move(Foo):
        mov     rax, rdi
        mov     edx, DWORD PTR [rsi]
        mov     DWORD PTR [rdi], edx
        ret