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
- 在这样的函数中,您可能希望调用
上的函数,以(i)窃取其资源,或(ii)将其视为左值而不窃取其资源value
- 该语言允许您为case(i)调用
,告诉std::move()
可能会窃取资源f
- 该语言允许您将
作为左值传递给不带值
的函数,例如case(ii),因此您可以调用函数而不必担心这一点。如果希望std::move()
以后窃取资源,这可能是可取的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
的类型为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);
}