Подтвердить что ты не робот

С++, ссылки rvalue в параметрах функции

Я пытаюсь понять ссылки rvalue. Я видел, как они используются в конструкторах с такими вещами, как std::move и std::forward, но я до сих пор не понимаю, почему это не работает:

void func(string&& str)
{
    cout << str << endl;
}
int main(int argc, char* argv[])
{
    string s("string");
    func(s);
}

И это делает:

template<typename T>
void func(T&& str)
{
    cout << str << endl;
}
int main(int argc, char* argv[])
{
    string s("string");
    func(s);
}

Почему он работает с версией шаблона функции?

4b9b3361

Ответ 1

Как и в случае с @Peter, тип T выводится как string&, а в правиле слияния ссылок С++ указано:

Т & и ⇒ T &//из С++ 98
Т && и ⇒ T &//новое для С++ 0x
Т && & ⇒ T &//новое для С++ 0x
Т && & & ⇒ T & &//new для С++ 0x

Итак,

Ответ 2

Некоторые формальные объяснения в дополнение к @songyuanyao ответ:

N4296::14.8.2.1 [temp.deduct.call]:

Вывод аргумента шаблона производится путем сравнения каждой функции тип шаблона шаблона (назовите его P) с типом соответствующего аргумент вызова (назовите его A), как описано ниже.

N4296::14.8.2.1/3 [temp.deduct.call]:

Ссылка на пересылку ссылку rvalue на параметр cv-unqualified. Если P является пересылка ссылки и аргумент - lvalue, тип "lvalue ссылка на A" используется вместо A для вывода типа.

Стандарт также предоставляет следующий пример:

template <class T> int f(T&& heisenreference);
template <class T> int g(const T&&);
int i;
int n1 = f(i); // calls f<int&>(int&)
int n2 = f(0); // calls f<int>(int&&)
int n3 = g(i); // error: would call g<int>(const int&&)

Это именно ваш случай.

Ответ 3

Поскольку внутри шаблона && имеет другое значение, он называется универсальной ссылкой.

Функция шаблона с параметром && (обратная ссылка) означает, что параметр может использоваться как ссылка или rvalue-ссылка.

В вашем случае шаблон выводится как string& и поэтому он работает.

Для работы с сырой функцией вы должны сделать это:

void func(string&& str)
{
    cout << str << endl;
}
int main(int argc, char* argv[])
{
    string s("string");
    func(std::move(s)); // move the string
    func(std::string("string")); // this is an rvalue and it is fine
}

Полное объяснение универсальных ссылок можно найти здесь: https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers