Если разрешено макросов , то это кажется выполнимым.
Первая попытка (хорошо, но не идеально ...)
int main() {
Vector<int, 4> vec;
vec[0] = 1; // same as: vec.t1 = 1;
vec[1] = 2; // same as: vec.t2 = 2;
vec[2] = 3; // same as: vec.t3 = 3;
vec[3] = 4; // same as: vec.t4 = 4;
std::cout << vec.t1 + vec.t2 + vec.t3 + vec.t4; // 10
}
Для достижения вышеуказанного:
#define VAR_NAME(num) t##num
#define DefineVector(num) \
template<typename T> \
struct Vector<T, num> : Vector<T, num-1> { \
T VAR_NAME(num); \
T& operator[](int index) { \
if(index == num-1) return VAR_NAME(num); \
return Vector<T, num-1>::operator[](index); \
} \
}
template<typename T, size_t N>
struct Vector;
template<typename T>
struct Vector<T, 1> {
T t1;
T& operator[](int index) {
// in case index != 0 this is UB
return t1;
}
};
DefineVector(2);
DefineVector(3);
DefineVector(4);
// TODO:
// replace 3 declarations above with a single *DefineVectorsRecursively(4);*
// by using recursive macros
// see: https://stackoverflow.com/questions/12447557/can-we-have-recursive-macros
// leaving this as a further exercise...
http://coliru.stacked -crooked.com / a / 42625e9c198e1e58
РЕДАКТИРОВАТЬ : добавлен оператор [] для устранения проблемы, поднятой в комментарии.
Вторая попытка: с более хорошими именами полей
ОП запросил, чтобы у полей были более хорошие имена, такие как x, y, z.
Это вызов,Но на помощь приходят макросы:
int main() {
Vector<int, 3> vec;
vec[0] = 1;
vec[1] = 2;
vec[2] = 3;
std::cout << vec.x + vec.y + vec.z; // 6
}
Со следующим кодом:
#include <boost/preprocessor/variadic/size.hpp>
template<typename T, size_t DIMENSIONS>
struct Vector;
#define DefineVector(VAR, ...) \
template<typename T> \
struct Vector<T, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__) + 1> \
: Vector<T, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)> { \
T VAR; \
T& operator[](int index) { \
if(index == BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)) return VAR; \
return Vector<T, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)>::operator[](index); \
} \
}
#define DefineVector1(VAR) \
template<typename T> \
struct Vector<T, 1> { \
T VAR; \
T& operator[](int index) { \
/* in case index != 0 this is UB */ \
return VAR; \
} \
}
DefineVector1(x);
DefineVector(y, x);
DefineVector(z, y, x);
// TODO: create recursive macro for DefineVector(z, y, x)
// that will create the two above recursively
Код: http://coliru.stacked -crooked.com / a / 2550eede71dc9b5e
Но подождите, оператор [] не так эффективен
У меня была мысль о более эффективном операторе [] в случае, если T - это стандартное расположение введите со следующей реализацией:
#define DefineVector(VAR, ...) \
template<typename T> \
struct Vector<T, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__) + 1> \
: Vector<T, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)> { \
T VAR; \
T& operator[](int index) { \
if constexpr(std::is_standard_layout_v<T>) { \
return *(&VAR - (BOOST_PP_VARIADIC_SIZE(__VA_ARGS__) - index)); \
} else { \
if(index == BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)) return VAR; \
return Vector<T, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)>::operator[](index); \
} \
} \
}
Попытка (BAD): http://coliru.stacked -crooked.com / a / d367e770f107995f
К сожалению - приведенная выше оптимизация недопустима
Для представленной реализации любой Vector с DIMENSIONS> 1 равен не стандартным классом макета (даже если T равен) потому что он имеет члены как в базовом классе, так и в производном классе :
10.1 [class.prop]
[3] Класс S - это стандартная схемакласс, если он: ...
[3.6] содержит все нестатические члены-данные и битовые поля в классе, а его базовые классы впервые объявлены в том же классе ...
Таким образом, приведенная выше попытка оптимизации имеет неопределенное поведение - компилятор не обязан сохранять адрес членов в иерархии наследования в их порядке.
Первоначальное решение все еще действует.