C++模板问题

azp*_*are 0 c++ templates

有人可以解释以下代码的输出吗?

#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);
}
Run Code Online (Sandbox Code Playgroud)

输出是

First method

Second method

Second method
Run Code Online (Sandbox Code Playgroud)

我不明白为什么.不应该最后调用assign激活第一个版本,因为(a + b)不返回const A对象?

GMa*_*ckG 7

(a + b) 但是,它返回一个临时对象,因此只能绑定到一个常量引用.


Joh*_*itb 7

表达式不仅具有值和类型,还具有值类别.这个类别可以

  • 左值:这些表达式通常引用指针的声明对象,引用,函数或取消引用结果.
  • xvalue:这是生成未命名的右值引用的结果.Rvalue引用是由T&&而不是创建的T&.它们是C++ 11概念,你可以在这里忽略它们.仅为完整起见而提及.
  • prvalue:这些是对非引用类型(如A(10))的转换或计算/指定值的结果,如422 + 3.

左值引用需要左值表达式进行初始化.也就是说,以下内容无效:

A &x = A(10);
Run Code Online (Sandbox Code Playgroud)

这背后的原因是只有左值表达式指的是适合并且用于保持活动的时间比仅在初始化期间更长的时间.就像,声明的对象一直存在,直到退出它的块(如果它是一个本地非静态变量)或直到程序结束(如果它被声明在函数和类之外).rvalue表达式A(10)指的是在初始化完成时已经死亡的对象.如果你说了以下内容,它就没有任何意义,因为纯粹的值10根本就没有地址,但是引用需要它们绑定的某种身份,这在实践中是通过获取地址来实现的他们的目标在编译器内部

int &x = 10; // makes totally no sense
Run Code Online (Sandbox Code Playgroud)

但对于const引用,C++有一个后门.当使用prvalue初始化时,如果表达式引用对象,则const左值引用将自动延长对象的生命周期.如果表达式具有非对象值,C++将创建一个具有该表达式值的临时对象,并延长该临时对象的生命周期,将对该临时值的引用绑定:

// 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; 
Run Code Online (Sandbox Code Playgroud)

在你的情况下会发生什么?

现在编译器在您的情况下,因为您提供了一个临时对象,将选择具有A const&参数类型而不是A&参数类型的版本.