2010-06-08 15 views
8

¿Me podría explicar la diferencia entre el mecanismo de los siguientes:temporales C++ rvalue en plantilla

int function(); 

template<class T> 
void function2(T&); 

void main() { 
    function2(function()); // compiler error, instantiated as int & 

    const int& v = function(); 
    function2(v); // okay, instantiated as const int& 
} 

es mi razonamiento correcto con respecto a la creación de instancias? ¿por qué no se crea la primera instancia como const T&?

Gracias

Respuesta

3

Porque function devuelve un valor no const. Solo los objetos pueden ser const, porque almacenan algún estado que podría modificarse si no fuera const. Lo que regresas allí no es un objeto, sino un valor puro. Conceptualmente, no son modificables (como las constantes de enumeración, por ejemplo), pero no están const (como, de nuevo, constantes de enumeración).

+2

@aca Para ser más precisos, [los valores r no pertenecientes a la clase siempre tienen tipos cv no calificados] (http: // stackoverflow.com/questions/2169932/non-class-rvalues-always-have-cv-un-kalified-types) ;-) Para class-types, hay una distinción entre rvalues ​​modificables y valores de configuración, por lo que, en general, el 'const' es * no * superfluo! Puede llamar a métodos no const en valores r modificables y así cambiar los objetos subyacentes. Por ejemplo, 'std :: string (" hello ") .append (" world! ")'. – fredoverflow

+0

@FredOverflow sí, buen punto. Observe que los valores de matriz se califican de la misma manera (el Estándar dice que no lo son, pero no son los menos; no puede escribir 'struct A {const int a [1];}; .. A(). A [0] = 0;' en la mayoría de los compiladores (excepto en Comeau, donde puede), pero si elimina el 'const', puede (ha habido preguntas en usenet y en otros lugares sobre esto, aún no se ha encontrado una solución). También observe que cualquier no- class/type/rvalue no es un objeto. Class-type/array-type rvalues ​​son objetos, por lo tanto const tiene sentido para ellos (ver nota al pie en 4.1/1 en el estándar). –

+0

@FredOverflow me pregunto qué @aca comentó que usted respondió? ¿Eliminó su comentario? –

0

En esta línea

function2(function()); 

después vuelve FUNCTION2, el argumento de que pasa a ella podría tener su cambio de valor, pero ya que devuelve la función() y es simplemente asignar a una variable temporal , pero lo que sucedería con esta variable temporal después de que se salga del alcance es el problema, es por eso que las quejas del compilador.

0

Para compilar la primera llamada, es necesario definir la función 2 con el parámetro T & & - esto es rvalue, referencia al objeto temporal. En la segunda llamada, v es una referencia lvalue, está bien. Si su compilador no es compatible con las referencias rvalue, la primera llamada se puede compilar solo con el parámetro T, sin referencia.

2

Creo que se puede confundir entre los valores de r y el calificador const. function devuelve un rvalue no const temporal de tipo int, por lo que el compilador deduce que T sea int, como debería ser. Como usted señala, puede enlazar un temporal a una ref constante (C++ 03 12.2/5), pero el compilador no agregará calificadores cv para hacer una llamada a función bien formada. Como no puede controlar la función de plantilla, hay dos formas de evitar esto (además de la solución que publicó).

(1) explícitos parámetros de plantilla: function2<const int>(function())

(2) cv calificar retorno: const int function();

Ambas soluciones están bien formadas. (1) parece la mejor solución, en mi humilde opinión, ya que (2) es poco convencional y tonto.

Editar: En realidad, el tipo deducido puede ser más cv-calificado que el argumento para un argumento de plantilla ref, pero solo si la deducción de tipo de lo contrario no (C++ 03 14.8.2.1/3). En este caso, la deducción del tipo no falla, pero da como resultado una llamada de función mal formada (SFINAE no se aplica, porque la especialización de la función de la plantilla no está mal formada).

Si la intención del autor de la plantilla era no modificar el argumento, debe declararse como un argumento de referencia constante, por lo que puede tratarse de un error en la biblioteca de plantillas o modificar el argumento, en cuyo caso lo que está haciendo fallará cuando la función intente modificar el argumento.

Editar: Como FredOverflow señala, los valores de clase no siempre son cv no calificados por el estándar 3.10/9. Entonces (2), que funciona bajo gcc 4.3, es en realidad un error de compilación (gcc < 4.5, según FredOverflow).

+1

No hay diferencia alguna entre 'int function () 'y' const int function() ', porque [los valores de clase no siempre tienen tipos cv no calificados] (http://stackoverflow.com/questions/2169932/non-class-rvalues-always-have-cv-unqualified -types). – fredoverflow

+0

@FredOverflow. Idealmente no, pero es diferente a gcc;) – academicRobot

+0

@aca Hm? El problema mencionado en el hilo enlazado se ha corregido en el último compilador g ++. – fredoverflow