El siguiente código no se compila.
int a = 1, b = 2, c = 3;
int& arr[] = {a,b,c,8};
¿Qué dice el estándar C ++ sobre esto?
Sé que podría declarar una clase que contiene una referencia, luego crear una matriz de esa clase, como se muestra a continuación. Pero realmente quiero saber por qué el código anterior no se compila.
struct cintref
{
cintref(const int & ref) : ref(ref) {}
operator const int &() { return ref; }
private:
const int & ref;
void operator=(const cintref &);
};
int main()
{
int a=1,b=2,c=3;
//typedef const int & cintref;
cintref arr[] = {a,b,c,8};
}
Es posible usar en struct cintref
lugar de const int &
simular una matriz de referencias.
intlink value = 8;
funciona. comprueba si no crees.operator=
. Las referencias no pueden ser reubicadas. Si realmente quiere este tipo de semántica - aunque no he encontrado personalmente una situación en la que son útiles en la práctica - a continuación,std::reference_wrapper
sería la manera de hacerlo, ya que realmente almacena un puntero, pero hay referencias similares aoperator
s y no permite volver a colocar. ¡Pero entonces solo usaría un puntero!Respuestas:
Respondiendo a su pregunta sobre el estándar, puedo citar el Estándar C ++ §8.3.2 / 4 :
fuente
struct
miembro cuyo único miembro sea una referencia. Pero luego, al hacerlo, ahora tiene una referencia y un objeto principal para nombrar ... lo que ahora significa que puede indicar inequívocamente qué dirección desea. Parece obvio ... entonces, ¿por qué nadie lo ha dicho?What more is there to say?
Una razón de por qué ? Me interesa el Estándar, pero solo citarlo y asumir que ese es el final de la discusión parece una forma segura de destruir el pensamiento crítico de los usuarios, junto con cualquier potencial para que el lenguaje evolucione, por ejemplo, más allá de las limitaciones de omisión o restricción artificial Hay demasiado "porque el Estándar dice" aquí, y no lo suficiente "y es muy sensato decir eso, debido a las siguientes razones prácticas". No sé por qué los votos positivos fluyen tan ansiosamente hacia las respuestas que solo dicen lo primero sin siquiera tratar de explorar lo último.Las referencias no son objetos. No tienen almacenamiento propio, solo hacen referencia a objetos existentes. Por esta razón, no tiene sentido tener matrices de referencias.
Si desea un objeto liviano que haga referencia a otro objeto, puede usar un puntero. Solo podrá usar a
struct
con un miembro de referencia como objetos en matrices si proporciona una inicialización explícita para todos los miembros de referencia para todas lasstruct
instancias. Las referencias no se pueden inicializar por defecto.Editar: Como señala jia3ep, en la sección estándar sobre declaraciones hay una prohibición explícita sobre las matrices de referencias.
fuente
Esta es una discusión interesante. Claramente, las matrices de referencias son completamente ilegales, pero en mi humilde opinión, la razón por la cual no es tan simple como decir 'no son objetos' o 'no tienen tamaño'. Señalaría que las matrices en sí mismas no son objetos completos en C / C ++: si se opone a eso, intente crear instancias de algunas clases de plantillas stl utilizando una matriz como parámetro de plantilla de 'clase' y vea qué sucede. No puede devolverlos, asignarlos, pasarlos como parámetros. (un parámetro de matriz se trata como un puntero). Pero es legal hacer matrices de matrices. Las referencias tienen un tamaño que el compilador puede y debe calcular: no puede sizeof () una referencia, pero puede hacer una estructura que contenga nada más que referencias. Tendrá un tamaño suficiente para contener todos los punteros que implementan las referencias. Usted puede'
De hecho, puede agregar esta línea a la definición de estructura
... y ahora tengo algo que se parece MUCHO a una serie de referencias:
Ahora, esto no es una matriz real, es una sobrecarga del operador; no hará cosas que las matrices normalmente hacen como sizeof (arr) / sizeof (arr [0]), por ejemplo. Pero hace exactamente lo que quiero que haga una serie de referencias, con C ++ perfectamente legal. Excepto (a) es difícil configurar más de 3 o 4 elementos, y (b) está haciendo un cálculo usando un montón de? , pero no obstante la indexación). Me gustaría ver un tipo muy limitado de "matriz de referencia" que realmente puede hacer esto. Es decir, una matriz de referencias no se trataría como una matriz general de cosas que son referencias, sino que sería una nueva 'matriz de referencia' hacer con plantillas).
Esto probablemente funcionaría, si no le importa este tipo de desagradable: reescriba '* this' como una matriz de int * 's y devuelva una referencia hecha desde uno: (no recomendado, pero muestra cómo la' matriz 'adecuada trabajaría):
fuente
std::tuple<int&,int&,int&> abcref = std::tie( a,b,c)
- que crea una "matriz" de referencias que sólo pueden ser indexados por constantes de tiempo de compilación usando std :: get. Pero no puedes hacerstd::array<int&,3> abcrefarr = std::tie( a,b,c)
. Tal vez hay una manera de hacerlo que no conozco. Me parece que debería haber una manera de escribir una especialización de lastd::array<T&,N>
cual se puede hacer esto, y por lo tanto una funciónstd::tiearray(...)
que devuelve uno de ellos (o permitirstd::array<T&,N>
aceptar el inicializador que contiene direcciones = {& v1, & v2, etc.)?:
std::array<T,N>
código muy simple y fácil de definir en la aplicación no se agregó a std :: hasta c ++ 11, presumiblemente porque es vergonzoso tener esto sin forma de ¿= {1,2,3};
Fue ese 'hackeo de idiomas'?Comenta tu edición:
La mejor solución es
std::reference_wrapper
.Detalles: http://www.cplusplus.com/reference/functional/reference_wrapper/
Ejemplo:
fuente
reference_wrapper
.Una matriz se puede convertir implícitamente en un puntero, y el puntero a referencia es ilegal en C ++
fuente
Dado
int& arr[] = {a,b,c,8};
, ¿qué essizeof(*arr)
?En todas partes, una referencia se trata simplemente como la cosa misma, por lo
sizeof(*arr)
que simplemente debería serlosizeof(int)
. Pero esto haría que la aritmética del puntero de matriz en esta matriz sea incorrecta (suponiendo que las referencias no sean del mismo ancho que las ints). Para eliminar la ambigüedad, está prohibido.fuente
struct
cuyo único miembro es esa referencia y averiguar ...?Porque como muchos han dicho aquí, las referencias no son objetos. son simplemente alias. Es cierto que algunos compiladores pueden implementarlos como punteros, pero el estándar no fuerza / especifica eso. Y debido a que las referencias no son objetos, no puede señalarlas. Almacenar elementos en una matriz significa que hay algún tipo de dirección de índice (es decir, apuntando a elementos en un cierto índice); y es por eso que no puede tener matrices de referencias, porque no puede señalarlas.
Use boost :: reference_wrapper, o boost :: tuple en su lugar; o simplemente punteros.
fuente
Creo que la respuesta es muy simple y tiene que ver con reglas de referencias semánticas y cómo se manejan las matrices en C ++.
En resumen: las referencias pueden considerarse estructuras que no tienen un constructor predeterminado, por lo que se aplican las mismas reglas.
1) Semánticamente, las referencias no tienen un valor predeterminado. Las referencias solo se pueden crear haciendo referencia a algo. Las referencias no tienen un valor para representar la ausencia de una referencia.
2) Al asignar una matriz de tamaño X, el programa crea una colección de objetos inicializados por defecto. Como la referencia no tiene un valor predeterminado, crear una matriz de este tipo es semánticamente ilegal.
Esta regla también se aplica a estructuras / clases que no tienen un constructor predeterminado. El siguiente ejemplo de código no se compila:
fuente
Object
, sólo hay que asegurarse de inicializar todos ellos:Object objects[1] = {Object(42)};
. Mientras tanto, no puede crear una serie de referencias, incluso si las inicializa todas.Puede acercarse bastante con esta estructura de plantilla. Sin embargo, debe inicializar con expresiones que son punteros a T, en lugar de T; y así, aunque puede hacer fácilmente un 'fake_constref_array' de manera similar, no podrá vincularlo a los valores como se hizo en el ejemplo del OP ('8');
-> A = 0 B = 7 X = {0,8,0}
fuente
Un objeto de referencia no tiene tamaño. Si escribe
sizeof(referenceVariable)
, le dará el tamaño del objeto al que hace referenciareferenceVariable
, no el de la referencia en sí. No tiene un tamaño propio, por lo que el compilador no puede calcular cuánto tamaño requeriría la matriz.fuente
Cuando almacena algo en una matriz, su tamaño debe ser conocido (ya que la indexación de la matriz depende del tamaño). Según el estándar de C ++ No se especifica si una referencia requiere almacenamiento o no, por lo que no sería posible indexar una matriz de referencias.
fuente
struct
, mágicamente todo se vuelve especificado, bien definido, garantizado y de tamaño determinista. ¿Por qué, por lo tanto, existe esta diferencia aparentemente totalmente artificial?struct
confiere el envoltorio , algunas buenas respuestas posibles comienzan a sugerir, pero para mí, nadie lo ha hecho aún, a pesar de que este es uno de los desafíos inmediatos para todos los comunes razones por las cuales no puedes usar referencias sin envolver.Solo para agregar a toda la conversación. Dado que las matrices requieren ubicaciones de memoria consecutivas para almacenar el elemento, por lo tanto, si creamos una matriz de referencias, no se garantiza que estén en una ubicación de memoria consecutiva, por lo que el acceso será un problema y, por lo tanto, ni siquiera podemos aplicar todas las operaciones matemáticas en formación.
fuente
Considere una variedad de punteros. Un puntero es realmente una dirección; así que cuando inicializa la matriz, le está diciendo de manera análoga a la computadora, "asigne este bloque de memoria para contener estos números X (que son direcciones de otros elementos)". Entonces, si cambia uno de los punteros, solo está cambiando lo que apunta; sigue siendo una dirección numérica que se encuentra en el mismo lugar.
Una referencia es análoga a un alias. Si declarara una serie de referencias, básicamente le estaría diciendo a la computadora, "asigne esta gota de memoria amorfa que consiste en todos estos elementos diferentes dispersos".
fuente
struct
cuyo único miembro es una referencia resulta en algo completamente legal, predecible y no amorfo? ¿Por qué un usuario debe ajustar una referencia para obtener mágicamente poderes con capacidad de matriz, o es solo una restricción artificial? En mi opinión, ninguna respuesta ha abordado directamente esto. Supongo que la refutación es 'El objeto de ajuste asegura que puede usar la semántica de valores, en la forma del objeto de ajuste, por lo que asegura que puede tener las garantías de valores, que son necesarias porque, por ejemplo, ¿cómo se podría desambiguar entre el elemento y la dirección del árbitro'? ... ¿Es eso lo que querías decir?En realidad, esta es una mezcla de sintaxis C y C ++.
Usted debe o bien utilizar matrices C puros, que no puede ser de referencias, ya que son parte de referencia C ++ solamente. O sigue el camino de C ++ y usa la clase
std::vector
ostd::array
para su propósito.En cuanto a la parte editada: aunque
struct
es un elemento de C, usted define un constructor y funciones de operador, que lo convierten en C ++class
. En consecuencia, sustruct
no compilaría en C puro!fuente
std::vector
ostd::array
tampoco puede contener referencias. El estándar C ++ es bastante explícito que ningún contenedor puede.