c++ pod lvalue rvalue

c++ - PODs, no-PODs, rvalue y lvalues



(3)

En mi entendimiento, tanto int () como A () deberían ser valores, ¿no?

Correcto, la expresión T() es siempre un valor para los tipos T escalares y definidos por el usuario. Mientras no esté involucrada la const , la expresión T() es un valor modificable , para ser más precisos.

La asignación que involucra tipos escalares requiere un lvalor modificable en el lado izquierdo del operador de asignación. Como int() no es un valor lime, no puede asignarlo a int() .

Para los tipos definidos por el usuario, la asignación es una función miembro especial, y las funciones miembro también pueden llamarse en valores (consulte la sección 10 de la sección 3.10). Es por eso que A().operator=(a) está bien formado.

¿Alguien podría explicar los detalles en términos de valores, valores, POD y no POD? ¿La razón por la que la primera expresión marcada a continuación no está bien mientras que la segunda marcada a continuación está bien? En mi entendimiento, tanto int () como A () deberían ser valores, ¿no?

struct A {}; int main() { int i; A a; int() = i; //Not OK (error). A() = a; //OK. return 0; }


De ¿C ++ valora la inicialización de un typedef POD? , que cita el estándar:

La expresión T (), donde T es un especificador de tipo simple (7.1.5.2) para un tipo de objeto completo no de matriz o el tipo vacío (posiblemente cv calificado), crea un rvalor del tipo especificado, que es valor -inicializado

Por lo tanto, int () es un rvalor y no se puede asignar a, como viste en tu primer caso.

A () no sería un especificador de tipo simlle y, por lo tanto, A () produce un lvalue


Los valores son lo que se obtiene de las expresiones (una simplificación útil tomada del estándar C, pero no redactada en C ++ standardese). Los valores de L son "valores de localización". Los valores pueden ser utilizados como valores. Las referencias siempre son valores l, incluso si const.

La principal diferencia que debe tener en cuenta se puede resumir en un solo elemento: no puede tomar la dirección de un valor (de nuevo, no es estándar, sino una generalización útil de las reglas). O para decirlo de otra manera, no puede fijar una ubicación precisa para un valor de r. Si pudiera, entonces tendría un valor de l . (Sin embargo, puede enlazar una constante y un valor de r para "arreglarlo en su lugar", y 0x está cambiando las reglas drásticamente).

Los tipos definidos por el usuario (UDT), sin embargo, son ligeramente especiales: puede convertir cualquier valor en un valor l, si la interfaz de la clase lo permite:

struct Special { Special& get_lvalue() { return *this; } }; void f() { // remember "Special()" is an rvalue Special* p = &Special().get_lvalue(); // even though you can''t dereference the // pointer (because the object is destroyed), you still just took the address // of a temporary // note that the get_lvalue() method doesn''t need to operate on a const // object (though that would be fine too, if the return type matched) }

Algo similar está sucediendo para su A() = a , excepto a través del operador de asignación suministrado por el compilador, para convertir el valor A() en *this . Para citar el estándar, 12.8 / 10:

Si la definición de la clase no declara explícitamente un operador de asignación de copia, uno se declara implícitamente . El operador de asignación de copia declarada implícitamente para una clase X tendrá el formulario

X& X::operator=(const X&)

Y luego continúa con más calificaciones y especificaciones, pero eso es lo importante aquí. Ya que es una función miembro, puede invocarse en rvalues, como Special :: get_lvalue puede ser, como si hubiera escrito A().operator=(a) lugar de A() = a .

El int() = 1 está explícitamente prohibido como lo descubrió, ya que ints no tiene operator = implementado de la misma manera. Sin embargo, esta ligera discrepancia entre los tipos no importa en la práctica (al menos no la que he encontrado).

POD significa datos antiguos sin formato y es una colección de requisitos que especificar el uso de memcpy es equivalente a copiar. Non-POD es cualquier tipo para el que no puedes usar memcpy para copiar (el opuesto natural de POD, nada oculto aquí), que suele ser la mayoría de los tipos que escribirás en C ++. Ser POD o no-POD no cambia ninguno de los anteriores, y es realmente un problema aparte.