这是引用到非常量绑定到临时的实例吗?

Is this an instance of a reference-to-non-const binding to a temporary?

本文关键字:实例 绑定 引用 非常 常量      更新时间:2023-10-16

免责声明:这个问题是为了理解。我将在现场使用boost::lexical_cast。不过,它在某些地方出现在现实世界中。


对"内联"lex-cast 方法进行以下尝试:

#include <string>
#include <sstream>
#include <iostream>
int main()
{
    const std::string s = static_cast<std::ostringstream&>(
       std::ostringstream() << "hi" << 0
    ).str();
    std::cout << s;
}

结果类似于0x804947c0,因为与"hi"一起工作的operator<<是一个自由函数,其LHS必须接受std::ostream&,而临时std::ostringstream()不能绑定到引用到非const。唯一剩下的比赛是在 RHS†† 上获得const void*operator<<

现在让我们交换操作数:

#include <string>
#include <sstream>
#include <iostream>
int main()
{
    const std::string s = static_cast<std::ostringstream&>(
       std::ostringstream() << 0 << "hi"
    ).str();
    std::cout << s;
}

结果是 "0hi" .

这主要是有道理的,因为取intoperator<<是基ostream†††的成员函数,因此,可以临时调用。该操作的结果是对ostream基的引用,下一个operator<<被链接到该基,即将其读取为(std::ostringstream() << 0) << "hi"

但是,为什么对"hi"的操作会继续产生预期的结果呢?LHS上的参考不是暂时的吗?


让我们专注于C++03;我被告知,由于右值的包罗万象运算符,第一个示例实际上可能在 C++11 中按"预期"工作。

[C++03: 27.6.2.1]: template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&,charT*);

††[C++03: 27.6.2.1]: basic_ostream<charT,traits>& operator<<(const void* p);

†††[C++03: 27.6.2.1]: basic_ostream<charT,traits>& operator<<(int n);

原因很简单。如果你读了我问的问题:

std::ostringstream 打印 C 字符串的地址而不是其内容。

您会注意到,获取"正确"引用而不是临时引用的技巧是在对象上调用一个方法(由于某种原因不限于不绑定限制(,该方法将返回引用。

在纳瓦兹上面的回答中,他打电话给std::ostream& std::ostream::flush(),在你的例子中:

std::ostringstream() << 0 << "hi"

你打电话给std::ostringstream& std::ostringstream::operator<<(int).

相同的结果。

令人惊讶的行为是由于ostream混杂的实现:一些operator<<是成员方法,而另一些是自由函数。

您可以通过在对象上实现 X& ref() 方法来简单地测试它:

struct X { X& ref(); };
void call(X& x);
int main() {
    call(X{});       // error: cannot bind X& to a temporary
    call(X{}.ref()); // OK
}

编辑:但为什么X&(ref的结果(没有被同等对待?

这是一个分类问题。临时是prvalue,而参考是lvalue。仅允许引用绑定到lvalue

当然,由于方法可以在rvalue(因此prvalue(上调用,并且这些方法可能会返回对调用它们的对象的引用,我们可以很容易地绕过愚蠢的(1(引用只允许绑定到lvalue限制...

(1(这也与rvalue可以绑定到常量引用的事实不一致。

LHS上的参考不是暂时的吗?

它是对临时(返回值(的左值引用,临时(返回值(仍然是左值

,因此可以绑定到左值引用。

寿命而不是l/rvalueness的角度考虑临时性。