考虑以下代码:
struct foo
{
int a;
};
foo q() { foo f; f.a =4; return f;}
int main()
{
foo i;
i.a = 5;
q() = i;
}
没有编译器抱怨它,即使是Clang。为什么q() = ...
行是正确的?
考虑以下代码:
struct foo
{
int a;
};
foo q() { foo f; f.a =4; return f;}
int main()
{
foo i;
i.a = 5;
q() = i;
}
没有编译器抱怨它,即使是Clang。为什么q() = ...
行是正确的?
q()
返回一个结构,然后为它分配一个值。怎么了
Answers:
不,当且仅当它是引用时,函数的返回值才是L值(C ++ 03)。(5.2.2 [expr.call] / 10)
如果返回的类型是基本类型,则将是编译错误。(5.17 [expr.ass] / 1)
之所以可行,是因为允许您在const
类类型的r值上调用成员函数(甚至是非成员函数),并且的分配foo
是实现定义的成员函数:foo& foo::operator=(const foo&)
。第5节中对运算符的限制仅适用于内置运算符(5 [expr] / 3),如果重载解析为某个运算符选择了一个重载函数调用,则该函数调用的限制将适用。
这就是为什么有时建议将类类型的const
对象作为对象返回的原因(例如const foo q();
),但是这可能对C ++ 0x产生负面影响,在C ++ 0x中它可能会阻止移动语义按预期工作。
std::cout << "Hello, world" << std::endl
。第一个operator<< ()
返回一个左值,您可以在其上调用第二个operator<< ()
。因此,这种对返回值进行调用的方法比许多人想像的更为普遍。
The Design and Evolution of C++
:这是这一概念的起源,这些概念多年来已发展成为C ++设计的经验法则:用户定义类型和内置类型应相对于语言规则表现出相同的行为并接受该语言及其相关工具提供了相同程度的支持。当理想化被制定时,内置类型得到了最好的支持,但是C ++超越了这个目标,因此与用户定义类型相比,内置类型现在获得的支持稍差。
cout
它确实返回一个左值(它本身并通过引用返回*this
),而不是按值返回。所以有点不同。
std::cout << "duh" << std::endl
,operator<<
所有返回非常量引用(均为左值),并且由于运算符都需要非常量引用作为其第一个参数,因此原始std::ostream
对象不能为右值。在其他示例中(我想这是问题的动机),非const函数是在临时函数上调用的。
因为可以将结构分配给您,并且您q()
返回的副本,struct foo
所以它会将返回的结构分配给所提供的值。
在这种情况下,这实际上并没有执行任何操作,因为该结构之后超出了范围,并且您一开始就没有对其进行引用,因此无论如何都无法对其进行任何操作(在此特定代码中)。
这更有意义(尽管仍然不是真正的“最佳实践”)
struct foo
{
int a;
};
foo* q() { foo *f = new malloc(sizeof(foo)); f->a = 4; return f; }
int main()
{
foo i;
i.a = 5;
//sets the contents of the newly created foo
//to the contents of your i variable
(*(q())) = i;
}
int blah() { int f = 4; return f; } int main() { int a = 99; blah() = a; }
结构有什么神奇之处吗?因为该代码无法编译。
int::operator=(int)
。这就是关于结构的“神奇”之处:它们具有默认方法。
s/nothing/anything/
一个有趣的应用程序:
void f(const std::string& x);
std::string g() { return "<tag>"; }
...
f(g() += "</tag>");
在这里,g() +=
修改临时项,这可能比创建其他临时项更快,+
因为分配给g()返回值的堆可能已经具有足够的备用容量来容纳</tag>
。
看到它运行在ideone.com上,带有GCC / C ++ 11。
现在,哪个计算新手谈到了优化和邪恶……?;-]。