C++ 为什么r值参考被指定为l值参考时会被视为l值参考?

C++ 为什么r值参考被指定为l值参考时会被视为l值参考?,c++,C++,考虑以下代码:() void f(int&&){ 模板 无效s(T和值) { 使用rv_ref=衰变&; 静态断言(是否相同); f(static_cast(value));//好的,但是我们已经检查了'value'已经是这种类型了 //f(值);//错误:没有匹配的函数 } int main() { s(9); } 让我畏缩的是,即使value的类型是int&,但当它被用作值[而不是表达式(与decltype)]时,它突然变成了l值 如何解释这一点才有意义?您可以这样写: 即使value的类

考虑以下代码:()

void f(int&&){
模板
无效s(T和值)
{
使用rv_ref=衰变&;
静态断言(是否相同);
f(static_cast(value));//好的,但是我们已经检查了'value'已经是这种类型了
//f(值);//错误:没有匹配的函数
}
int main()
{
s(9);
}
让我畏缩的是,即使
value
的类型是
int&
,但当它被用作值[而不是表达式(与
decltype
)]时,它突然变成了l值

如何解释这一点才有意义?

您可以这样写:

即使
value
的类型是int&,当它被用作值[而不是表达式(与decltype一样)]时,它突然变成了l值

考虑左值和右值的一种高级方法是,左值有名称,可以指定给
value
显然有一个名称,所以它是左值也就不足为奇了

考虑
std::move()
或静态强制转换的一种方法是,它不仅将其参数强制转换为正确的类型,而且还生成一个右值表达式

思考您的两个函数
s
f

  • 您的函数
    s
    可能接受右值引用,因为您希望对右值进行操作,例如,通过移动操作窃取右值的资源
  • 在这样的函数中,您可能希望调用
    value
    上的函数,以(i)窃取其资源,或(ii)将其视为左值而不窃取其资源
  • 该语言允许您为case(i)调用
    std::move()
    ,告诉
    f
    可能会窃取资源
  • 该语言允许您将
    作为左值传递给不带
    std::move()
    的函数,例如case(ii),因此您可以调用函数而不必担心这一点。如果希望
    s
    以后窃取资源,这可能是可取的

这个问题非常相似:

用作表达式的变量的名称始终是左值,即使变量的类型是右值引用。(虽然<代码> DECTYPE < /COD>有一些附加的规则,而不仅仅是看表达式的值类别)。这是C++语言的一个有意的选择,因为否则它会很容易从变量中移动。

例如:

void debug_str_val(std::string var_name, std::string value);

void MyClass::set_name(const std::string& name)
{
    debug_str_val("name", name);
    m_name = name;
}

void MyClass::set_name(std::string&& name)
{
    debug_str_val("name", name);  // *
    m_name = std::move(name);
}
在标有
*
的行中,
名称
被视为左值,因此
调试(debug)str(u val)
获取该值的副本。(它可能会使用
const std::string&
参数,但它不这样做。)如果
name
被视为右值,则
debug\u stru\val
将从中移动,然后将不可预测的值分配给
m\u name


一旦对象有了名称,它就可以被多次使用,即使该名称是右值引用。因此,C++默认使用LVE,让程序员说,当他们希望它被用作一个R值时,使用<代码> STD::移动< /COD>,或者有时“代码> STD::前进//CODE,或显式转换为RValk引用类型。< / P>任何有名称的东西都是LVEEEI认为Value<代码>这是一个通用引用()。然后,
value
的类型为
int&
[而不是
int&
]。而且一切都会像预期的那样工作(对吧?)。好的,我明白了。我从未想过类型推断取决于表达式[而不是表达式的类型]。我看看能不能把它吞下去。非常感谢。
void debug_str_val(std::string var_name, std::string value);

void MyClass::set_name(const std::string& name)
{
    debug_str_val("name", name);
    m_name = name;
}

void MyClass::set_name(std::string&& name)
{
    debug_str_val("name", name);  // *
    m_name = std::move(name);
}