C++0x const RValue referencia como parámetro de función


Estoy tratando de entender por qué alguien escribiría una función que toma una referencia const rvalue.

En el ejemplo de código a continuación, cuál es el propósito de la función de referencia const rvalue (devolviendo "3"). Y por qué la resolución de sobrecarga prefiere el const Rvalue por encima de la función de referencia const LValue (devolviendo "2").

#include <string>
#include <vector>
#include <iostream>

std::vector<std::string> createVector() { return std::vector<std::string>(); } 

//takes movable rvalue
void func(std::vector<std::string> &&p) { std::cout << "1"; }

//takes const lvalue
void func(const std::vector<std::string> &p)  { std::cout << "2"; }

//takes const rvalue???
//what is the point of const rvalue? if const I assume it is not movable?
void func(const std::vector<std::string> &&p) { std::cout << "3"; }

int main()
{
    func(createVector());
    return 0;
}
Author: MW_dev, 2011-06-10

2 answers

Los Lvalues prefieren fuertemente el enlace a las referencias lvalue, y de manera similar las referencias rvalue prefieren fuertemente el enlace a las referencias rvalue. Las expresiones modificables prefieren débilmente el enlace a una referencia no constante.

Así que cuando su compilador está haciendo la resolución de sobrecarga, comprueba si hay una sobrecarga que toma una referencia rvalue, porque eso se prefiere fuertemente. En este caso, dado que la experssion es un rvalue modificable, la sobrecarga de referencia rvalue gana.

En realidad hay use para referencias const rvalue, se pueden usar para asegurarse de que algo no se vincule a un rvalue. Recuerde que un rvalue se une a una referencia const lvalue, por lo tanto, si lo hizo:

template <typename T> void foo(const T& bar) { /* ... */ }

Y llamó a la función con:

foo(createVector());

Funcionaría bien. Sin embargo, a veces se desea asegurarse de que solo puede pasar lvalues a una función (este es el caso de std::ref para una). Puede lograr esto agregando una sobrecarga:

template <typename T> void foo(const T&&) = delete;

Recuerde, los rvalues prefieren fuertemente binding to rvalue references, and modifiable expressions prefer weakly binding to non-const references. Dado que tenemos una referencia const rvalue, básicamente significa que cada rvalue se unirá a esto, por lo tanto, si intenta pasar un rvalue a foo(), su compilador dará un error. Esta es la única manera de lograr tal funcionalidad, y por lo tanto a veces es útil.

 29
Author: reko_t,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-10 14:49:29

La resolución de sobrecarga prefiere const rvalue sobre const lvalue porque, bueno, es un rvalue y lo estás vinculando a una referencia rvalue, pero tienes que agregar const en ambos casos, por lo que la referencia rvalue definitivamente es preferible.

Estas cosas generalmente no tienen sentido - es mejor dejarlas enlazadas a las sobrecargas de const lvalue. los valores constantes no tienen ningún uso real.

 2
Author: Puppy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-10 14:11:33