Voici un moyen d'utiliser une classe proxy pour accéder aux éléments d'un tableau de membres par nom. Il est très C ++ et n'a aucun avantage par rapport aux fonctions d'accesseur renvoyant ref, sauf pour la préférence syntaxique. Cela surcharge l' ->
opérateur pour accéder aux éléments en tant que membres, donc pour être acceptable, il faut à la fois ne pas aimer la syntaxe des accesseurs ( d.a() = 5;
), ainsi que tolérer l'utilisation ->
avec un objet non pointeur. Je pense que cela pourrait également dérouter les lecteurs qui ne sont pas familiers avec le code, donc cela pourrait être plus une astuce intéressante que quelque chose que vous souhaitez mettre en production.
La Data
structure de ce code inclut également les surcharges pour l'opérateur d'indexation, à des éléments indexés d'accès à l' intérieur de son ar
élément de réseau, ainsi que begin
et les end
fonctions, par itération. En outre, tous ces éléments sont surchargés de versions non const et const, qui, à mon avis, devaient être incluses par souci d'exhaustivité.
Lorsque Data
's ->
est utilisé pour accéder à un élément par son nom (comme ceci:) my_data->b = 5;
, un Proxy
objet est renvoyé. Puis, comme cette Proxy
rvalue n'est pas un pointeur, son propre ->
opérateur est appelé automatiquement en chaîne, qui renvoie un pointeur sur lui-même. De cette façon, l' Proxy
objet est instancié et reste valide pendant l'évaluation de l'expression initiale.
La construction d'un Proxy
objet remplit ses 3 membres de référence a
, b
et c
selon un pointeur passé dans le constructeur, qui est supposé pointer vers un tampon contenant au moins 3 valeurs dont le type est donné comme paramètre de modèle T
. Ainsi, au lieu d'utiliser des références nommées qui sont membres de la Data
classe, cela économise de la mémoire en remplissant les références au point d'accès (mais malheureusement, en utilisant ->
et non l' .
opérateur).
Afin de tester dans quelle mesure l'optimiseur du compilateur élimine toutes les indirection introduites par l'utilisation de Proxy
, le code ci-dessous comprend 2 versions de main()
. La #if 1
version utilise les opérateurs ->
et []
, et la #if 0
version exécute l'ensemble de procédures équivalent, mais uniquement en accédant directement Data::ar
.
La Nci()
fonction génère des valeurs entières d'exécution pour l'initialisation des éléments du tableau, ce qui empêche l'optimiseur de simplement brancher des valeurs constantes directement dans chaque std::cout
<<
appel.
Pour gcc 6.2, en utilisant -O3, les deux versions de main()
génèrent le même assembly (basculez entre #if 1
et #if 0
avant le premier main()
à comparer): https://godbolt.org/g/QqRWZb
#include <iostream>
#include <ctime>
template <typename T>
class Proxy {
public:
T &a, &b, &c;
Proxy(T* par) : a(par[0]), b(par[1]), c(par[2]) {}
Proxy* operator -> () { return this; }
};
struct Data {
int ar[3];
template <typename I> int& operator [] (I idx) { return ar[idx]; }
template <typename I> const int& operator [] (I idx) const { return ar[idx]; }
Proxy<int> operator -> () { return Proxy<int>(ar); }
Proxy<const int> operator -> () const { return Proxy<const int>(ar); }
int* begin() { return ar; }
const int* begin() const { return ar; }
int* end() { return ar + sizeof(ar)/sizeof(int); }
const int* end() const { return ar + sizeof(ar)/sizeof(int); }
};
// Nci returns an unpredictible int
inline int Nci() {
static auto t = std::time(nullptr) / 100 * 100;
return static_cast<int>(t++ % 1000);
}
#if 1
int main() {
Data d = {Nci(), Nci(), Nci()};
for(auto v : d) { std::cout << v << ' '; }
std::cout << "\n";
std::cout << d->b << "\n";
d->b = -5;
std::cout << d[1] << "\n";
std::cout << "\n";
const Data cd = {Nci(), Nci(), Nci()};
for(auto v : cd) { std::cout << v << ' '; }
std::cout << "\n";
std::cout << cd->c << "\n";
//cd->c = -5; // error: assignment of read-only location
std::cout << cd[2] << "\n";
}
#else
int main() {
Data d = {Nci(), Nci(), Nci()};
for(auto v : d.ar) { std::cout << v << ' '; }
std::cout << "\n";
std::cout << d.ar[1] << "\n";
d->b = -5;
std::cout << d.ar[1] << "\n";
std::cout << "\n";
const Data cd = {Nci(), Nci(), Nci()};
for(auto v : cd.ar) { std::cout << v << ' '; }
std::cout << "\n";
std::cout << cd.ar[2] << "\n";
//cd.ar[2] = -5;
std::cout << cd.ar[2] << "\n";
}
#endif