Inn*_*der 16 c++ one-definition-rule c++11 pass-by-const-reference forwarding-reference
想象一下以下简化代码:
#include <iostream>
void foo(const int& x) { do_something_with(x); }
int main() { foo(42); return 0; }
Run Code Online (Sandbox Code Playgroud)
(1)除了优化之外,42传递给什么时会发生什么foo?
编译器是否在某处(在堆栈上?)并将其地址传递给foo?
(1a)标准中是否有任何内容规定在这种情况下要做什么(或者它是否严格取决于编译器)?
现在,想象一下略有不同的代码
#include <iostream>
void foo(const int& x) { do_something_with(x); }
struct bar { static constexpr int baz = 42; };
int main() { foo(bar::baz); return 0; }
Run Code Online (Sandbox Code Playgroud)
它不会链接,除非我定义int bar::baz;(由于ODR?).
(2)除了ODR之外,为什么编译器不能对上面的42做什么呢?
简化事物的一种明显方法是定义foo为:
void foo(int x) { do_something_with(x); }
Run Code Online (Sandbox Code Playgroud)
但是,如果是模板,会怎么做?例如:
template<typename T>
void foo(T&& x) { do_something_with(std::forward<T>(x)); }
Run Code Online (Sandbox Code Playgroud)
(3)是否有一种优雅的方式来foo表示接受x原始类型的价值?或者我是否需要专注于SFINAE或其他一些?
编辑:修改内部发生的事情,foo因为它与这个问题无关.
T.C*_*.C. 11
编译器是否在某处(在堆栈上?)并将其地址传递给
foo?
const int创建一个类型的临时对象,使用prvalue表达式初始化42,并绑定到引用.
实际上,如果foo没有内联,则需要在堆栈上分配空间,存储42到其中并传递地址.
标准中是否有任何内容规定在这种情况下要做什么(或者它是否完全取决于编译器)?
除了ODR之外,为什么编译器不能对上面的42做什么呢?
因为根据语言,引用绑定到对象bar::baz,除非编译器确切地知道foo在编译调用时正在做什么,所以它必须假设这是重要的.例如,如果foo包含一个assert(&x == &bar::baz);,则不得触发foo(bar::baz).
(在C++中17,baz是隐式地内联作为constexpr静态数据成员 ;不需要单独的定义.)
是否有一种优雅的方式来告诉原始类型的价值
foo接受x?
在没有分析数据显示传递引用实际上导致问题的情况下,这样做通常没什么意义,但如果你真的需要这样做是因为某些原因,添加(可能是SFINAE约束的)重载将是要走的路.
| 归档时间: |
|
| 查看次数: |
1048 次 |
| 最近记录: |