通过 reference/value 过载

Pass by reference/value overload

试图弄清楚为什么在以下代码中没有引起重载歧义:

float foo2(float& i)
{
    cout << "call from reference" << endl;
    return i;
}
float foo2(float i)
{
    cout << "call from non reference"<<endl;
    return i;
}
int main()
{
    cout<<foo2(2); // print "call from non reference"
}

调用了非传参的foo2。为什么?如何调用传递引用参数的foo2?

您为 foo2 提供的参数 2 是右值,不能作为引用。因此不能用它调用接受引用的函数。

The foo2 whose parameters not passed by reference is called. Why?

因为您不能通过引用将常量或任何计算表达式传递给采用非常量引用的函数。要通过引用传递表达式,您需要一个可赋值的值——可以出现在赋值表达式左侧的值。由于 2 不能出现在赋值表达式的左侧,因此它不能用于调用需要引用的函数。当引用为 const 时,您可以传递任何内容,因为 C++ 将创建一个临时变量,将表达式分配给它,并将引用传递给采用 const 引用的函数。

How to call the foo2 that pass reference parameters?

没有明显的方法可以做到这一点,因为当您传递一个变量或另一个可以成为引用的表达式时,编译器会抱怨您进行了模棱两可的调用:

float f;
foo2(f); // <<== This will not compile

不过,有一种方法可以调用它:您可以制作一个仅匹配两个函数签名之一的函数指针,并使用它来进行调用:

typedef float (*fptr_with_ref)(float&);

int main()
{
    cout<<foo2(2) << endl; // print "call from non reference"
    fptr_with_ref foo2ptr(foo2); // Only one overload matches
    float n = 10;
    cout<<foo2ptr(n) << endl; // Calls foo2(float&)
}

Demo.

你的问题是用 C++ 术语,而不是设计术语。 C++ 以某种方式支持事物,因为它在设计方面很有意义。 C++ 允许你做很多事情,但如果你想用它制作好的软件,你不能只遵守字面的 C++ 规则,你需要走得更远。实际上,这意味着您最终会制定自己的规则。

在你的情况下 - 好吧,如果我没有实际更改函数中的变量,我永远不会创建引用变体。

如果您自己采用这样的 'rules',那么您会立即明白为什么 ref 函数不绑定:首先,更改松散常量有什么意义?

如果您制定了正确的规则,您会发现它们得到了 C++ 的完美支持。 Like ... 函数更改对象:传递非常量引用。没变化?常量参考选修的?常量指针。接管内存管理?非常量指针。

请注意,这只是开始,尤其是当多线程发挥作用时。您必须向函数的 'contract' 添加内容。 const ref 的示例:调用后对象必须保留 'alive' 吗?对象可以在调用过程中改变吗?等等。