Le code suivant ne compile pas.
int a = 1, b = 2, c = 3;
int& arr[] = {a,b,c,8};
Que dit la norme C ++ à ce sujet?
Je sais que je pourrais déclarer une classe qui contient une référence, puis créer un tableau de cette classe, comme indiqué ci-dessous. Mais je veux vraiment savoir pourquoi le code ci-dessus ne se compile pas.
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};
}
Il est possible d'utiliser struct cintref
au lieu de const int &
pour simuler un tableau de références.
intlink value = 8;
fonctionne. vérifiez si vous ne croyez pas.operator=
. Les références ne peuvent pas être réinstallées. Si vous voulez vraiment telle sémantique - même si je ne l' ai pas personnellement trouvé une situation dans laquelle ils sont utiles dans la pratique - alorsstd::reference_wrapper
serait la façon de le faire, car il stocke en fait un pointeur , mais fournit comme référenceoperator
s et ne permet rasseyant. Mais alors j'utiliserais juste un pointeur!Réponses:
En réponse à votre question sur la norme, je peux citer la norme C ++ §8.3.2 / 4 :
la source
struct
dont le seul membre est une référence. Mais alors, ce faisant, vous avez maintenant à la fois une référence et un objet parent à nommer ... ce qui signifie maintenant que vous pouvez indiquer sans ambiguïté quelle adresse vous voulez. Cela semble évident ... alors pourquoi personne ne l'a dit?What more is there to say?
Une raison pour laquelle ? Je suis tout au sujet de la norme, mais le simple fait de le citer et de supposer que c'est la fin de la discussion semble être un moyen infaillible de détruire la pensée critique des utilisateurs - ainsi que tout potentiel d'évolution du langage, par exemple au-delà des limites d'omission ou restriction artificielle. Il y a trop de «parce que la norme dit« ici - et pas assez »et il est très raisonnable de dire cela, pour les raisons pratiques suivantes». Je ne sais pas pourquoi les votes positifs affluent si avidement aux réponses qui ne disent que la première sans même essayer d'explorer la seconde.Les références ne sont pas des objets. Ils n'ont pas de stockage propre, ils font simplement référence aux objets existants. Pour cette raison, il n'a pas de sens d'avoir des tableaux de références.
Si vous voulez un objet léger qui référence un autre objet, vous pouvez utiliser un pointeur. Vous ne pourrez utiliser un
struct
avec un membre de référence comme objets dans des tableaux que si vous fournissez une initialisation explicite pour tous les membres de référence pour toutes lesstruct
instances. Les références ne peuvent pas être initialisées par défaut.Edit: Comme le note jia3ep, dans la section standard sur les déclarations, il y a une interdiction explicite sur les tableaux de références.
la source
C'est une discussion intéressante. Il est clair que les tableaux de références sont carrément illégaux, mais à mon humble avis, la raison pour laquelle ce n'est pas si simple que de dire «ils ne sont pas des objets» ou «ils n'ont pas de taille». Je soulignerais que les tableaux eux-mêmes ne sont pas des objets à part entière en C / C ++ - si vous vous y opposez, essayez d'instancier des classes de modèle stl en utilisant un tableau comme paramètre de modèle de `` classe '', et voyez ce qui se passe. Vous ne pouvez pas les retourner, les assigner, les passer en paramètres. (un paramètre de tableau est traité comme un pointeur). Mais il est légal de créer des tableaux de tableaux. Les références ont une taille que le compilateur peut et doit calculer - vous ne pouvez pas sizeof () une référence, mais vous pouvez créer une structure ne contenant que des références. Il aura une taille suffisante pour contenir tous les pointeurs qui implémentent les références. Vous pouvez'
En fait, vous pouvez ajouter cette ligne à la définition de struct
... et maintenant j'ai quelque chose qui ressemble beaucoup à un tableau de références:
Maintenant, ce n'est pas un vrai tableau, c'est une surcharge d'opérateurs; il ne fera pas des choses que les tableaux font normalement comme sizeof (arr) / sizeof (arr [0]), par exemple. Mais il fait exactement ce que je veux qu'un tableau de références fasse, avec un C ++ parfaitement légal. Sauf (a) c'est difficile de configurer plus de 3 ou 4 éléments, et (b) il fait un calcul en utilisant un tas de?: Ce qui pourrait être fait en utilisant l'indexation (pas avec l'indexation normale de C-pointer-calcul-sémantique , mais indexation tout de même). J'aimerais voir un type de «tableau de référence» très limité qui peut réellement le faire. C'est-à-dire qu'un tableau de références ne serait pas traité comme un tableau général de choses qui sont des références, mais plutôt un nouveau 'tableau-de-références' faire avec des modèles).
cela fonctionnerait probablement, si cela ne vous dérange pas ce genre de méchant: refondre '* this' comme un tableau d'int * et renvoyer une référence faite à partir de l'un: (non recommandé, mais cela montre comment le bon 'tableau' travaillerait):
la source
std::tuple<int&,int&,int&> abcref = std::tie( a,b,c)
- qui crée un «tableau» de références qui ne peuvent être indexées que par des constantes à la compilation en utilisant std :: get. Mais tu ne peux pas fairestd::array<int&,3> abcrefarr = std::tie( a,b,c)
. Il y a peut-être un moyen de le faire que je ne connais pas. Il me semble qu'il devrait y avoir un moyen d'écrire une spécialisationstd::array<T&,N>
qui peut le faire - et donc une fonctionstd::tiearray(...)
qui en renvoie une (ou qui permettestd::array<T&,N>
d'accepter un initialiseur contenant des adresses = {& v1, & v2 etc})?:
std::array<T,N>
, facilement défini dans le code de l'application, n'a pas été ajouté à std :: jusqu'à C ++ 11, probablement parce qu'il est verruqueux d'avoir cela sans moyen de= {1,2,3};
Est - ce que c'était du «piratage de langage»?Commentez votre modification:
La meilleure solution est
std::reference_wrapper
.Détails: http://www.cplusplus.com/reference/functional/reference_wrapper/
Exemple:
la source
reference_wrapper
.Un tableau est implicitement convertible en pointeur, et le pointeur vers référence est illégal en C ++
la source
Étant donné
int& arr[] = {a,b,c,8};
, qu'est-ce que c'estsizeof(*arr)
?Partout ailleurs, une référence est traitée comme étant simplement la chose elle-même, elle
sizeof(*arr)
devrait donc l' êtresizeof(int)
. Mais cela rendrait l'arithmétique du pointeur de tableau erronée sur ce tableau (en supposant que les références ne sont pas de la même largeur est ints). Pour éliminer l'ambiguïté, c'est interdit.la source
struct
dont le seul membre est cette référence et découvrez ..?Car comme beaucoup l'ont dit ici, les références ne sont pas des objets. ce sont simplement des alias. Il est vrai que certains compilateurs peuvent les implémenter en tant que pointeurs, mais la norme ne force / ne spécifie pas cela. Et comme les références ne sont pas des objets, vous ne pouvez pas les pointer. Stocker des éléments dans un tableau signifie qu'il existe une sorte d'adresse d'index (c'est-à-dire, pointant vers des éléments à un certain index); et c'est pourquoi vous ne pouvez pas avoir de tableaux de références, car vous ne pouvez pas les pointer.
Utilisez plutôt boost :: reference_wrapper ou boost :: tuple; ou juste des pointeurs.
la source
Je pense que la réponse est très simple et qu'elle a à voir avec les règles sémantiques de références et la façon dont les tableaux sont gérés en C ++.
En bref: les références peuvent être considérées comme des structures qui n'ont pas de constructeur par défaut, donc toutes les mêmes règles s'appliquent.
1) Sémantiquement, les références n'ont pas de valeur par défaut. Les références ne peuvent être créées qu'en référençant quelque chose. Les références n'ont pas de valeur pour représenter l'absence de référence.
2) Lors de l'allocation d'un tableau de taille X, le programme crée une collection d'objets initialisés par défaut. Puisque la référence n'a pas de valeur par défaut, la création d'un tel tableau est sémantiquement illégale.
Cette règle s'applique également aux structures / classes qui n'ont pas de constructeur par défaut. L'exemple de code suivant ne compile pas:
la source
Object
, il vous suffit de vous assurer de les initialiser tous:Object objects[1] = {Object(42)};
. En attendant, vous ne pouvez pas créer un tableau de références, même si vous les initialisez toutes.Vous pouvez être assez proche avec cette structure de modèle. Cependant, vous devez initialiser avec des expressions qui sont des pointeurs vers T, plutôt que T; et ainsi, bien que vous puissiez facilement créer un 'fake_constref_array' de la même manière, vous ne pourrez pas le lier à rvalues comme dans l'exemple de l'OP ('8');
-> A = 0 B = 7 X = {0,8,0}
la source
Un objet de référence n'a pas de taille. Si vous écrivez
sizeof(referenceVariable)
, cela vous donnera la taille de l'objet référencé parreferenceVariable
, pas celle de la référence elle-même. Il n'a pas de taille propre, c'est pourquoi le compilateur ne peut pas calculer la taille requise par le tableau.la source
Lorsque vous stockez quelque chose dans un tableau, sa taille doit être connue (car l'indexation du tableau dépend de la taille). Selon le standard C ++ Il n'est pas spécifié si une référence nécessite ou non du stockage, par conséquent l'indexation d'un tableau de références ne serait pas possible.
la source
struct
, tout devient comme par magie spécifié, bien défini, garanti et de taille déterministe. Pourquoi, par conséquent, cette différence apparemment totalement artificielle existe-t-elle?struct
confère l'emballage , de bonnes réponses possibles commencent à se suggérer - mais pour moi, personne ne l'a encore fait, bien que ce soit l'un des défis immédiats à tous les justifie pourquoi vous ne pouvez pas utiliser des références non emballées.Juste pour ajouter à toute la conversation. Étant donné que les tableaux nécessitent des emplacements mémoire consécutifs pour stocker l'élément, donc si nous créons un tableau de références, il n'est pas garanti qu'elles seront à un emplacement mémoire consécutif, l'accès sera donc un problème et nous ne pouvons même pas appliquer toutes les opérations mathématiques sur tableau.
la source
Considérez un tableau de pointeurs. Un pointeur est vraiment une adresse; Ainsi, lorsque vous initialisez le tableau, vous dites de manière analogue à l'ordinateur, "allouez ce bloc de mémoire pour contenir ces numéros X (qui sont les adresses d'autres éléments)". Ensuite, si vous changez l'un des pointeurs, vous changez simplement ce qu'il pointe; c'est toujours une adresse numérique qui se trouve elle-même au même endroit.
Une référence est analogue à un alias. Si vous deviez déclarer un tableau de références, vous diriez essentiellement à l'ordinateur, "allouez cette goutte amorphe de mémoire constituée de tous ces différents éléments éparpillés."
la source
struct
dont le seul membre est une référence aboutit-il à quelque chose de complètement légal, prévisible et non amorphe? Pourquoi un utilisateur doit-il envelopper une référence pour qu'il obtienne comme par magie des pouvoirs capables de faire des tableaux, ou s'agit-il simplement d'une restriction artificielle? Aucune réponse de l'OMI n'a abordé ce problème directement. Je suppose que la réfutation est `` L'objet d'emballage garantit que vous pouvez utiliser la sémantique de la valeur, sous la forme de l'objet d'emballage, de sorte qu'il garantit que vous pouvez avoir les garanties de valeurs, qui sont nécessaires parce que, par exemple, comment lever l'ambiguïté entre l'élément et l'adresse de l'arbitre '' ... C'est ce que tu voulais dire?En fait, il s'agit d'un mélange de syntaxe C et C ++.
Vous devez soit utiliser des tableaux C purs, qui ne peuvent pas être des références, car les références font partie de C ++ uniquement. Ou vous utilisez la méthode C ++ et utilisez la classe
std::vector
oustd::array
pour vos besoins.Quant à la partie éditée: même si le
struct
est un élément de C, vous définissez un constructeur et des fonctions d'opérateur, ce qui en fait un C ++class
. Par conséquent, vousstruct
ne compileriez pas en C pur!la source
std::vector
oustd::array
ne peut pas contenir de références non plus. La norme C ++ est assez explicite qu'aucun conteneur ne peut.