Esta é uma maneira de usar uma classe proxy para acessar elementos em uma matriz de membro por nome. É muito C ++ e não tem nenhum benefício em relação às funções de acesso de retorno de referência, exceto para preferência sintática. Isso sobrecarrega o ->
operador para acessar elementos como membros, portanto, para ser aceitável, é necessário não gostar da sintaxe de acessadores ( d.a() = 5;
), bem como tolerar o uso ->
com um objeto que não seja um ponteiro. Espero que isso também confunda os leitores não familiarizados com o código, então isso pode ser mais um truque interessante do que algo que você deseja colocar em produção.
A Data
estrutura neste código também inclui sobrecargas para o operador subscrito, para acessar elementos indexados dentro de seu ar
membro de matriz, bem como begin
eend
funções , para iteração. Além disso, todos eles estão sobrecarregados com versões não constantes e const, que eu senti que precisavam ser incluídas para completar.
Quando Data
s ->
é usado para acessar um elemento por nome (como este my_data->b = 5;
:), um Proxy
objeto é retornado. Então, como esse Proxy
rvalue não é um ponteiro, seu próprio ->
operador é chamado de cadeia automática, que retorna um ponteiro para si mesmo. Dessa forma, o Proxy
objeto é instanciado e permanece válido durante a avaliação da expressão inicial.
A construção de um Proxy
objeto preenche seus 3 membros de referência a
, b
e de c
acordo com um ponteiro passado no construtor, que se supõe apontar para um buffer contendo pelo menos 3 valores cujo tipo é dado como o parâmetro do modelo T
. Portanto, em vez de usar referências nomeadas que são membros da Data
classe, isso economiza memória ao preencher as referências no ponto de acesso (mas, infelizmente, usando ->
e não o .
operador).
Para testar o quão bem o otimizador do compilador elimina todos os caminhos indiretos introduzidos pelo uso de Proxy
, o código a seguir inclui 2 versões de main()
. A #if 1
versão usa os operadores ->
e []
, e a #if 0
versão executa o conjunto equivalente de procedimentos, mas apenas acessando diretamenteData::ar
.
A Nci()
função gera valores inteiros de tempo de execução para inicializar elementos da matriz, o que impede o otimizador de apenas inserir valores constantes diretamente em cadastd::cout
<<
chamada.
Para gcc 6.2, usando -O3, ambas as versões de main()
geram o mesmo assembly (alterne entre #if 1
e #if 0
antes do primeiro main()
para comparar): 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