Вопрос о шаблонах C ++ - PullRequest
       0

Вопрос о шаблонах C ++

0 голосов
/ 17 сентября 2011

Может кто-нибудь объяснить вывод следующего кода?

#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?

Ответы [ 3 ]

7 голосов
/ 17 сентября 2011

Выражение не только имеет значение и тип, но также имеет значение категория .Эта категория может быть

  • Значение l: Эти выражения обычно ссылаются на объявленные объекты, ссылки, функции или результаты разыменования указателей.
  • Значение x: это результат создания безымянной ссылки на rvalue.R-значения ссылок создаются T&& вместо T&.Это концепция C ++ 11, и вы можете проигнорировать их здесь.Упоминается только для полноты.
  • Значение: Это результаты приведения к не ссылочным типам (например, A(10)) или вычисления / указания значения, например, 42 или 2 + 3.

Ссылка lvalue требует выражения lvalue для инициализации.То есть следующее недопустимо:

A &x = A(10);

Причина этого заключается в том, что только выражения lvalue относятся к вещам, которые подходят и предназначены для того, чтобы оставаться в живых дольше, чем только на время инициализации.Например, объявленный объект действует до выхода из своего блока (если это была локальная нестатическая переменная) или до конца программы (если он был объявлен вне функций и классов).Выражение rvalue A(10) относится к объекту, который умирает уже после завершения инициализации.И если бы вы сказали следующее, это не имело бы никакого смысла, потому что чистые значения, такие как 10, вообще не имеют адреса, но ссылки требуют некоторой идентичности, с которой они связываются, что на практике реализуетсявзятие адреса их цели внутри компиляторов

int &x = 10; // makes totally no sense

Но для константных ссылок C ++ имеет бэкдор.При инициализации с помощью prvalue ссылка на const lvalue автоматически продлевает время жизни объекта, если выражение ссылается на объект.Если выражение имеет необъектное значение, 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; 

Чтопроисходит в вашем случае?

Теперь компилятор в вашем случае, поскольку вы предоставляете временный объект, будет выбирать версию с типом параметра A const&, а не с параметром A&.

7 голосов
/ 17 сентября 2011

(a + b) возвращает временный объект, и поэтому может быть привязан только к постоянной ссылке.

3 голосов
/ 17 сентября 2011

a+b возвращает временное значение, если вам было разрешено перехватить неконстантную ссылку на него, вы могли бы изменить его и что дальше?Временный объект выходит из области видимости, и внесенные в него изменения не могут быть зафиксированы приложением.В C ++ 03 временные привязки будут связаны с константными ссылочными типами.

Кстати, это не имеет ничего общего с шаблонами.Перепишите свой пример, используя прямые буквы «А», и вы увидите то же поведение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...