这是引用到非常量绑定到临时的实例吗?
Is this an instance of a reference-to-non-const binding to a temporary?
免责声明:这个问题是为了理解。我将在现场使用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"
.
这主要是有道理的,因为取int
的operator<<
是基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的角度考虑临时性。
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 在基于范围的for循环中使用结构化绑定声明
- 使用 LuaBridge 将 LuaJIT 绑定到C++会导致"PANIC: unprotected error"
- 尝试通过OCI例程从Oracle获取blob数据,但出现错误:ORA-01008:并非所有变量都绑定
- 在使用GPU支持编译Tensorflow时,会遇到CUDA_TOOLKIT_PATH未绑定变量
- 视觉studo 2019中的漫画和静态/动态绑定
- 将自由函数绑定为类成员函数
- 绑定派生类方法C++从实例范围之外的分隔 std::function 变量调用
- 将类实例函数绑定到 v8::FunctionTemplate
- 尝试将实例传递到绑定的函数C
- 将 std::function 绑定到不同对象实例的同一函数
- Boost::将sigaction函数引用绑定到实例
- 将 Java 类实例绑定到C++类实例
- 是否可以为现有类的实例绑定新属性,例如 c++ 中的 JavaScript?
- 运行时绑定和模板实例化
- std::将成员函数绑定到 nullptr 处的实例,导致看似随机的 this 指针
- LuaBind:如何将类的特定实例绑定到Lua
- 使用std::bind分别绑定参数和对象实例
- 确定性随机数生成器绑定到实例(线程无关)
- 这是引用到非常量绑定到临时的实例吗?