问题 更改基本类型和类类型的返回值


有这样的代码:

#include <iostream>
#include <string>

int returnnumber() { return 2; }
std::string returntext() { return "siema"; }

int main() {

    std::cout << (returntext() += "cze") << std::endl; // siemacze
    //std::cout << (returnnumber() += 2) << std::endl; error: lvalue required as left operand of assignment

    return 0;
} 

为什么可以更改std :: string的返回值,但不能更改int?


10213
2017-10-22 17:08


起源



答案:


因为 std::string 是一个定义的类类型 += 运算符作为成员函数。

并且标准允许您在rvalues上调用成员函数。

这是一个愚蠢的结果

struct S { int x; };
S foo() { return S(); }

int main()
{
    foo() = S();    // OK, uses member assignment operator.
    foo().x = 666;  // !Nah, can't assign to rvalue of built-in type.
}

编译结果:

关于ONLINE_EVALUATION_BETA2的Comeau C / C ++ 4。3。10。1(2008年10月6日11:28:09)
版权所有1988-2008 Comeau Computing。版权所有。
MODE:严格错误C ++ C ++ 0x_extensions

“ComeauTest.c”,第7行:错误:表达式必须是可修改的左值
      foo()。x = 666; //!Nah,无法分配到内置类型的右值。
      ^

在编译“ComeauTest.c”时检测到1错误。

然而,编制者对于他们如何严格地应用这一微妙的规则,或者根本不同,有所不同(或曾经不同)。

干杯和hth。,


10
2017-10-22 17:13



好吧,但是 int 运营商 += 也定义了。 - Vlad
@downvoter:为什么? - Vlad
@anonymous downvoter:请解释你的downvote,以便其他人可以从你的见解中受益,或忽略一些愚蠢的理由。 - Cheers and hth. - Alf
@Vlad:for int 该 += 是个 内建的  operator=,而为 std::string 它是一个成员函数。我正在更新我的答案,以便更清楚。干杯&hth。, - Cheers and hth. - Alf
@Vlad:我不知道,但对于一个非常相似的问题,Bjarne Stroustrup(语言设计师)回答说这主要是一次历史性事故。他原本打算坐下来解决这个问题,但发现他没有时间。有很多就是那样......干杯, - Cheers and hth. - Alf


答案:


因为 std::string 是一个定义的类类型 += 运算符作为成员函数。

并且标准允许您在rvalues上调用成员函数。

这是一个愚蠢的结果

struct S { int x; };
S foo() { return S(); }

int main()
{
    foo() = S();    // OK, uses member assignment operator.
    foo().x = 666;  // !Nah, can't assign to rvalue of built-in type.
}

编译结果:

关于ONLINE_EVALUATION_BETA2的Comeau C / C ++ 4。3。10。1(2008年10月6日11:28:09)
版权所有1988-2008 Comeau Computing。版权所有。
MODE:严格错误C ++ C ++ 0x_extensions

“ComeauTest.c”,第7行:错误:表达式必须是可修改的左值
      foo()。x = 666; //!Nah,无法分配到内置类型的右值。
      ^

在编译“ComeauTest.c”时检测到1错误。

然而,编制者对于他们如何严格地应用这一微妙的规则,或者根本不同,有所不同(或曾经不同)。

干杯和hth。,


10
2017-10-22 17:13



好吧,但是 int 运营商 += 也定义了。 - Vlad
@downvoter:为什么? - Vlad
@anonymous downvoter:请解释你的downvote,以便其他人可以从你的见解中受益,或忽略一些愚蠢的理由。 - Cheers and hth. - Alf
@Vlad:for int 该 += 是个 内建的  operator=,而为 std::string 它是一个成员函数。我正在更新我的答案,以便更清楚。干杯&hth。, - Cheers and hth. - Alf
@Vlad:我不知道,但对于一个非常相似的问题,Bjarne Stroustrup(语言设计师)回答说这主要是一次历史性事故。他原本打算坐下来解决这个问题,但发现他没有时间。有很多就是那样......干杯, - Cheers and hth. - Alf


内置类型的赋值运算符的左侧必须是可修改的 左值 但函数的返回值总是一个 右值 如果函数没有返回引用类型。

operator+= 是...的成员函数 std::string 你可以调用一个成员函数 右值 类类型。


2
2017-10-22 17:15



我想知道,为什么这样的不一致? - Vlad
你的意思是“任务操作员的左手边?” - Vaughn Cato
@VaughnCato:是的,我做到了。谢谢。 - CB Bailey


为了同样的原因

std::string("siema") += "cze";

作品。

您正在构建一个新对象并应用 operator += (哪一个 std::string 对它而言。

尝试使用它将无法正常工作,因为您的函数返回 rvalue。这将是:

2 += 2

你可以玩弄这个:

#include <iostream>
#include <string>

int& returnnumber() { int * k = new int; *k = 2; return *k; }
std::string returntext() { return "siema"; }

int main() {

    std::cout << (returntext() += "cze") << std::endl; // siemacze
    std::cout << (returnnumber() += 2) << std::endl; //no error
    std::string("siema") += "cze";
    return 0;
} 

但这会导致内存泄漏,所以不要这样做。它只是一个概念证明,返回一个 lvalue 会工作。


1
2017-10-22 17:18



嗨Luchian :)不 returntext 还返回一个右值? - Vlad
Charles Bailey写道:但是如果函数没有返回引用类型,函数的返回值总是一个rvalue。然后returntext返回rvalue或lvalue? - scdmb
我很困惑,去做一些阅读:) - Luchian Grigore
returntext 确实会返回一个类型的右值 std::string (3.10 / 5 in C ++ 03)。内置的赋值需要一个左值(这个规则继承自C,我想,虽然理论上C ++如果想要的话可​​能会改变)。但是,可以在rvalues上调用成员函数,包括作为成员重载的运算符。以来 int 没有任何成员函数,而 string 是的,这两条规则会导致不一致。在C ++ 11中有更多类型的*值,我仍然没有完全直接所以我不会尝试引用它,但效果是相同的。 - Steve Jessop
@SteveJessop感谢您的澄清。 - Luchian Grigore


returntext() 返回一个 std::string 可以在以后的阶段修改,比如说 +=operator。然而,尽管 returnnumber() 返回一个 int,函数本身正在返回 2 这是由defualt a const int 并且不可更改,这就是编译器抱怨的原因。


0
2017-10-22 20:58