在 C++ 中为用户定义类型与内置类型分配临时类型的差异 [重复]

Differences in Assigning to Temporaries for User-Defined vs Built-in Types in C++ [duplicate]

提问人:Sami 提问时间:10/3/2023 最后编辑:Sami 更新时间:10/3/2023 访问量:77

问:

我最近一直在研究 C++ 的复杂性,有一个特定的行为让我感到困惑:围绕临时工的规则和行为,尤其是关于获取他们的地址并分配给他们。

临时工分配:此外,我观察到我可以分配给 UDT 的非常量临时:

Rational a(1, 2), b(3, 4), c(5, 6);
(a * b) = c;  // This line compiles

但是,尝试将具有内置类型的按值(即 r 值)返回的函数分配给结果会导致编译错误:

int f(int x, int y) {
    return x;
}

int main() {
    f(10, 5) = 12;  // This line won’t compile
}

我的问题:临时工分配: 如何将 UDT 分配给非常量临时? 这种行为是否一致,在实践中应该使用还是避免? 我搜索了各种资源,但没有找到对这些行为的令人满意的解释。有人可以解释一下这些问题吗?

先谢谢你!

C++ 赋值运算符

评论

0赞 Eljay 10/3/2023
对我不起作用,我得到了.也许您的代码中存在您未提供的错误,因此最小的可重现示例会很有用。error: taking the address of a temporary object of type 'Rational'
1赞 Sami 10/3/2023
是的。有一个错误!对不起。但是我们仍然可以分配给用户定义的临时右值,但它不适用于内置类型!
2赞 Eljay 10/3/2023
但是我们仍然可以分配给用户定义的临时右值,但它不适用于内置类型!对于 UDT,如果需要,可以禁止分配给临时 UDT。
0赞 Sami 10/3/2023
好点子!通过这样做?friend const Rational 运算符*(const Rational& lhs ,const Rational& rhs) { return Rational (lhs.m_numerator * rhs.m_denominator, lhs.m_numerator * rhs.m_denominator);
1赞 Eljay 10/3/2023
通过执行成员函数:auto operator=(Rational const& b) & -> Rational&;

答:

2赞 Jan Schultke 10/3/2023 #1

唯一的原因是内置运算符在操作数的值类别方面有一定的要求。

赋值运算符 () 和复合赋值运算符都按从右到左的顺序分组。 所有这些都需要一个可修改的左值作为其左操作数;[...]=

- [expr.ass] 第1页

一元运算符的操作数应为某种类型的左值&T

- [expr.unary.op] 第 3 页

Fr 示例无效,因为是 prvalue。&44

运算符重载可以绕过这些规则,因为只需转换为函数调用。如果有一个重载运算符,你可以这样做,这将采用一个 prvalue 的地址。如果有一个重载运算符(实际上所有类类型都有),你可以执行分配给 prvalue 的操作。这些表达式对于内置 和 运算符是不可能的。&some_rationalRational&&Rational{}Rational=Rational{} = ...&=

请注意,您可以使用 ref-qualifiers 禁用此行为:

struct Rational {
    /* ... */

    // the & ref-qualifier means that the = operator only works with lvalues
    Rational& operator=(const Rational& other) &;
};

由于可以绑定到临时对象,因此对于具有限定符的成员函数,不可能实现相同的目的。最接近的是使用 C++23 的显式对象参数:const&const

template <std::same_as<const Rational> Self>
address_type operator&(this Self auto& r);

评论

0赞 Jarod42 10/3/2023
一!?^_^ 和 temporary 可以绑定到 const ref。operator=const
0赞 Sami 10/3/2023
感谢您的回复,所以我可以做“(a * b) = c;”但不能做“f(10, 5) = 12;”的原因是因为正如你所解释的。“你可以做 Rational{} = ...分配给 prvalue。这些表达式对于内置的 & 和 = 运算符是不可能的。