有人可以解释以下代码的输出吗?
#include <iostream>
template <class T>
void assign(T& t1, T& t2){
std::cout << "First method"<< std::endl;
t1 = t2;
}
template <class T>
void assign(T& t1, const T& t2) {
std::cout << "Second method"<< std::endl;
t1 = t2;
}
class A
{
public:
A(int a) : _a(a) {};
private:
friend A operator+(const A& l, const A& r);
int _a;
};
A operator+(const A& l, const A& r)
{
return A(l._a + r._a);
}
int main ()
{
A a = 1;
const A b = 2;
assign(a, a);
assign(a, b);
assign(a, a + b);
}
输出是
First method
Second method
Second method
我不明白为什么。由于 (a+b) 不返回 const A 对象,最后一次调用 assign 不应该激活第一个版本吗?
最佳答案
表达式不仅具有值和类型,而且还具有值类别。这个类别可以是
- 左值:这些表达式通常引用已声明的对象、引用、函数或指针的解引用结果。
- 一个 xvalue:这些是生成一个未命名的右值引用的结果。右值引用是由
T&&
而不是T&
创建的。它们是C++11的概念,这里可以忽略。仅出于完整性考虑而提及。 - 纯右值:这些是转换为非引用类型(如
A(10)
)或计算/指定值的结果,如42
或2 + 3
。
左值引用需要用于初始化的左值表达式。也就是说,以下是无效的:
A &x = A(10);
这背后的原因是,只有左值表达式指的是适合并旨在比仅在初始化期间存活更长时间的事物。就像,声明的对象在退出其 block (如果它是局部非静态变量)或直到程序结束(如果它在函数和类之外声明)之前一直存在。右值表达式 A(10)
指的是一个在初始化完成时已经死亡的对象。如果您说以下内容,那将毫无意义,因为像 10
这样的纯值根本没有地址,但是引用需要它们绑定(bind)的某种身份,这实际上是通过在编译器内部获取目标地址来实现的
int &x = 10; // makes totally no sense
但对于 const 引用,C++ 有一个后门。当用纯右值初始化时,const 左值引用将自动延长对象的生命周期(如果表达式引用一个对象)。如果表达式具有非对象值,C++ 会创建一个具有该表达式值的临时对象,并延长该临时对象的生命周期,将引用绑定(bind)到该临时对象:
// lifetime of the temporary object is lengthened
A const& x = A(10);
// lifetime of the automatically created temporary object is lengthened
int const& x = 10;
你的情况会怎样?
现在你的情况下的编译器,因为你提供了一个临时对象,将选择具有 A const&
参数类型而不是 A&
参数类型的版本。
关于C++ 模板问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7456943/