Hola, resulta que estoy portando el código de una aplicación C++ de VC 6 a GCC 4, y hay muchos lugares donde se usa un rvalue como parámetro a una función que espera una referencia del mismo tipo. Ejemplo:
void foo( int& a )
{
}
int main()
{
int a = 0;
foo( a ); // OK
foo( int(69) ); // Error
foo( (int&)int(69) ); // Error con GCC 4. GCC 3 se traga el cast.
return 0;
}
Obviamente, en el código real no se usan simples enteros, sino estructuras de datos más pesadas. En una ocasión anterior, portando una aplicación similar de VC6 a GCC 3.3, un cast me bastaba para forzar al compilador a tragarse el parámetro, pero el nuevo GCC 4 ya no admite trampa ninguna. Los casts modernos (static_cast, reinterpret_cast) también devuelven un error (lógicamente).
Aunque entiendo perfectamente porqué el código es ilegal desde el punto de vista del estándar de C++, y las diferencias entre tipos lvalue y rvalue, me gustaría saber si conocéis de algun 'workaround' para esta situación y así minimizar el código a modificar.
El código tal y como está tiene un comportamiento indefinido. Lo único más cercano a no serlo sin modificar la llamada está en cambiar el tipo del argumento de foo a const int& (porque el estándar de C++ especifica de manera deliberada que asociar un objeto temporal a una referencia a constante en la pila alarga el tiempo de vida del temporal al tiempo de vida de esa referencia), pero eso sólo te será útil si foo no modifica su argumento, lo cual posiblemente no sea el caso porque, de serlo, éste ya sería (tendría que ser) referencia a constante en primer lugar.
No hay manera definida por el estándar del lenguaje de pasar un objeto temporal a una función que toma una referencia a no constante como parámetro. Sólo los lvalues se pueden asociar a referencias a no constantes.
Hola, buenas.
Perdona la ignorancia, pero ¿qué significa utilizar el signo &?
Lo he buscado por Internet pero no encuentro nada que responda a mi pregunta.
Hasta lo que yo he estudiado, sólo he utilizado el signo * en los prototipos de las funciones y en sus declaraciones para indicar que se va a recibir la dirección de memoria de una variable (un puntero). Y el signo & lo he utlizado para pasar la direccion de una variable que no es un puntero ni un vector/matriz (si lo fuera ya no haría falta ningún signo) a una función de este tipo, como es el caso de la conocida función scanf.
¿Es algo de funciones que reciben otras funciones pasadas por parámetro, callback?
Gracias. Siento la ignorancia y el off-topic :)
Saludos.
Suponiendo que conozcas el tipo de parametro de foo y este sea definido se me ocurre que en algunos casos el workaround mas sencillo deberia ser usar un macro del tipo
#define foo(X) { int _temp_ =(X); foo( _temp_ ); }
Pero esto no es aplicable a todos los casos seguramente.
Lo mejor es que hables con la persona que hizo esta macana y le digas que escriba bien el codigo de forma que ande en todos los compiladores :P (seguramente a el tambien le va a interesar)
Saludos
@Jalbam: El uso del símbolo & en el código de arriba tiene que ver con el paso de parámetros a funciones por referencia (http://www.google.com/search?client=safari&rls=en-us&q=paso+de+par%C3%A1metros+por+referencia&ie=UTF-8&oe=UTF-8), una característica de C++ que no está en C.
Muchas gracias por la respuesta :)
La verdad es que no es la primera vez que lo veo pero no sabía qué era.
Por lo que he leido parece ser igual que cuando pasas por referencia un puntero pero esta vez es de forma "constante", sin poder modificar la variable a la que apunta.
Pues no,
para que sea constante tienes que poner el modificador "const"foo(const int& variable)
{
variable = 1; // error
}
foo(int& variable)
{
variable = 1; // valido!
}
La diferencia de la referencia es que siempre apunta a un elemento valido (o almenos asi deberia)
En cambio un puntero puede apuntar a NULL
Otra diferencia es que la referencia es inoperable, no puedes desplazarte sobre ella como en un puntero (excepto que hagas unos casting a punteros y luego a referencia)
Y otra tambien es que la referencia es un elemento nuevo de C++ y aporta mas datos al compilador.
Saludos
Por cierto, gracias a Davur y Pogacha. En efecto, añadir el 'const' al parámetro por referencia soluciona la papeleta. ¡Gracias!
En realidad el crédito es de Davur, yo también recién me desayuno que pasar un objeto temporal por referencia como parámetro no constante de una función es un error y no tan solo una práctica insegura.
VC6 te permite hacer esas aberraciones :X
Para la gente que no entienda el uso de & (en este caso jalbam), es exactamente lo mismo que usar un puntero constante. Solo que así se simplifica la sintaxis y se puede referenciar de una forma muy fácil de escribir parámetros por referencias (valga la redundancia :D).
Yo, por mi parte, acostumbrado al GCC me he quedado boquiabierto al ver que Visual C++ se traga el código de Zaelsius. ¿Has probado a modificar el parámetro a en foo (compilando desde el Visual), a ver que pasa? ¿No sería código potencialmente inseguro?
LC0, no tiene por qué, a mi entender estas modificando una variable local de la función externa, otra cosa es que esa variable no tiene nombre, otra cosa es si no se hubiera casteado a int, porque entonces sí que estarias modificando una constante.
Es que en mi opinión carece de sentido tener pasar un valor constante para ser modificado, es igualq que hacer:
int a;
...
5 = a;
si, pero al hacer int(5) creo que ya no es una constante. Yo hablo a nivel de compilador, no de concepto.
Que hermoso sería el mundo si todos compilasemos con "-ansi -pedantic-errors" :P