#include <iostream>
#include <string>
#include <vector>
template <typename T>
using identity = T;
template <typename T>
using reference = T&;
template <template <class> typename F, template <template <class> class> class S>
struct soa_wrapper : S<F> {
S<reference> operator[](std::size_t i) {
auto& [x, y, activation, identifier] = *this;
return {x[i], y[i], activation[i], identifier[i]};
}
};
struct Point2D { double x, y; };
template<template <class> class F>
struct S {
F<int> x, y;
F<Point2D> activation;
F<std::string> identifier;
int abs2() const { return x * x + y * y; } // not defined for std::vector<int>
int& getX() { return x; }
void setX(int x_new) { x = x_new; }
};
int main() {
soa_wrapper<std::vector, S> my_array;
my_array.x = {0, 1, 2};
my_array.y = {0, 1, 2};
my_array.activation = {{0, 1}, {2, 3}, {4, 5}};
my_array.identifier = {"bla", "foo", "bar"};
my_array[1].setX(10);
my_array[1].getX();
for (int i = 0; i < 3; ++i) std::cout << my_array[i].abs2() << std::endl;
return 0;
}