Most type conversions are of a very specific form. Now they are very commmplicated:
auto id = [](auto& member, std::size_t) -> decltype(auto) { return member; };
return helper::apply_to_members<M, value_type&, proxy_type<reference, S>>(data[i], id);
Both the library code and the user code can be made much simpler by providing user defined conversion operators.
The folloeing code is just an example explaining the principle.
#include <span>
#include <vector>
template <class T>
using value = T;
template <class T>
using reference = T&;
template <template <class> class F>
struct S {
template <template <class> class F_out>
operator S<F_out>() { return {x, y, z}; }
F<int> x, y, z;
};
int main() {
S<std::vector> v {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
S<std::span> s = v;
S<value> a {1, 2, 3};
S<reference> s = a;
return 0;
}