将文字作为const ref参数传递

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到其中并传递地址.

标准中是否有任何内容规定在这种情况下要做什么(或者它是否完全取决于编译器)?

[dcl.init.ref].

除了ODR之外,为什么编译器不能对上面的42做什么呢?

因为根据语言,引用绑定到对象bar::baz,除非编译器确切地知道foo在编译调用时正在做什么,所以它必须假设这是重要的.例如,如果foo包含一个assert(&x == &bar::baz);,则不得触发foo(bar::baz).

(在C++中17,baz隐式地内联作为constexpr静态数据成员 ;不需要单独的定义.)

是否有一种优雅的方式来告诉原始类型的价值foo接受x

在没有分析数据显示传递引用实际上导致问题的情况下,这样做通常没什么意义,但如果你真的需要这样做是因为某些原因,添加(可能是SFINAE约束的)重载将是要走的路.