У меня есть шаблон класса, который выглядит так:
template<int n=3> struct Vec{
double Values[n];
};
Конечно, я могу получить доступ к элементам этого класса напрямую или с помощью метода, например:
double& x(){
return Values[0];
}
Но если бы я хотел сделать более интуитивно понятный код: вместо
Vec<3> v;
v.x() = 5.2;
Я хотел бы позволить пользователю сделать это:
v.x = 5.2
, Это не только каприз. Если у меня есть существующая библиотека, которая использует простые векторные структуры вида struct{double x,y,z;}
Я мог бы с помощью утилитарной типизации создать мой шаблонный класс, чтобы быть эффективным в этом случае. Конечно, я мог бы (возможно, я не уверен) передать в эту библиотеку предопределенную структуру ссылок — например:
struct{double &x=v.Values[0], &y=v.Values[1], &z=v.Values[2];}
но я боюсь, что это не самый простой способ получить цель.
Ах, конечно, я мог бы добавить параметры ссылочного типа в мою структуру, но это привело бы к увеличению размера элементов.
Вот один из способов получить тот же синтаксический эффект:
template<int n=3> struct Vec{
double Values[n];
};
template<int N> struct xyzAdapter;
template<> struct xyzAdapter<3>
{
xyzAdapter(Vec<3>& vec) : x(vec.Values[0]), y(vec.Values[1]), z(vec.Values[2]) {}
double& x;
double& y;
double& z;
};
template<int N> auto make_adapter(Vec<N>& vec)
{
return xyzAdapter<N>(vec);
}
int main()
{
Vec<3> point;
auto adapter = make_adapter(point);
adapter.x = 6;
}
Идти по другому пути не совсем так приятно. Не существует такого понятия, как массив ссылок, поэтому один из обходных путей — прибегнуть к массиву std::reference_wrapper
:
#include <tuple>
#include <array>
#include <functional>
#include <iostream>
template<int N = 3> struct Vector;
template<> struct Vector<3>
{
double x, y, z;
auto as_tuple() {
return std::tie(x, y, z);
}
};
template<std::size_t...Is, class Tuple>
auto as_array(std::index_sequence<Is...>, Tuple&& t)
{
return std::array<std::reference_wrapper<double>, sizeof...(Is)> {
std::get<Is>(t)...
};
}
template<int N> auto as_array(Vector<N>& v)
{
return as_array(std::make_index_sequence<N>(), v.as_tuple());
}
int main2()
{
Vector<3> point;
point.x = 6;
auto arr = as_array(point);
for (auto ref : arr) {
std::cout << ref.get() << std::endl;
}
return 0;
}
Других решений пока нет …