Dans la norme ISO C99/C11, de l'union de type beaucoup les jeux de mots est légal, donc vous pouvez l'utiliser à la place de l'indexation des pointeurs vers des non-tableaux (voir les divers autres réponses).
ISO C++ ne permet pas de l'union de type beaucoup les jeux de mots. GNU C++, comme une extension, et je pense que certains d'autres compilateurs qui ne supportent pas les extensions GNU, en général, ne l'appui de l'union de type beaucoup les jeux de mots. Mais cela ne veut pas vous aider à écrire strictement code portable.
Les dernières versions de gcc et clang, l'écriture d'une fonction de membre C++ à l'aide d'un switch(idx)
pour sélectionner un membre permettra d'optimiser loin pour constante à la compilation des indices, mais produira terrible branchu asm pour l'exécution des indices. Il n'y a rien d'intrinsèquement mauvais avec des switch()
pour cela; c'est tout simplement un incontournable-l'optimisation de bug dans le courant de compilateurs. Ils pourraient compilateur Slava' () la fonction de manière efficace.
La solution à cela est de faire dans l'autre sens: donner votre class/struct un membre de groupe, et d'écrire des fonctions d'accesseur pour attacher les noms d'éléments spécifiques.
struct array_data
{
int arr[3];
int &operator[]( unsigned idx ) {
// assert(idx <= 2);
//idx = (idx > 2) ? 2 : idx;
return arr[idx];
}
int &a(){ return arr[0]; } // TODO: const versions
int &b(){ return arr[1]; }
int &c(){ return arr[2]; }
};
Nous pouvons avoir un coup d'oeil à l'asm de sortie pour les différents cas d'utilisation, sur la Godbolt compilateur explorer. Ces sont complètes x86-64 fonctions V, avec la fuite instruction RET omis afin de mieux montrer ce que vous obtiendrez quand ils en ligne. BRAS/MIPS/tout ce qui serait similaire.
# asm from g++6.2 -O3
int getb(array_data &d) { return d.b(); }
mov eax, DWORD PTR [rdi+4]
void setc(array_data &d, int val) { d.c() = val; }
mov DWORD PTR [rdi+8], esi
int getidx(array_data &d, int idx) { return d[idx]; }
mov esi, esi # zero-extend to 64-bit
mov eax, DWORD PTR [rdi+rsi*4]
Par comparaison, @Slava réponse à l'aide d'un switch()
pour le C++ permet à l'asm de ce genre pour l'exécution, la variable d'index. (Code de la précédente Godbolt lien).
int cpp(data *d, int idx) {
return (*d)[idx];
}
# gcc6.2 -O3, using `default: __builtin_unreachable()` to promise the compiler that idx=0..2,
# avoiding an extra cmov for idx=min(idx,2), or an extra branch to a throw, or whatever
cmp esi, 1
je .L6
cmp esi, 2
je .L7
mov eax, DWORD PTR [rdi]
ret
.L6:
mov eax, DWORD PTR [rdi+4]
ret
.L7:
mov eax, DWORD PTR [rdi+8]
ret
C'est évidemment terrible, par rapport à la C (ou C++ de GNU) de l'union type beaucoup les jeux de mots version:
c(type_t*, int):
movsx rsi, esi # sign-extend this time, since I didn't change idx to unsigned here
mov eax, DWORD PTR [rdi+rsi*4]