Я хочу иметь тип, который имеет именованные элементы, а также является итеративным, поэтому нужно иметь возможность ссылаться на элементы по индексу, по метке или по каждому для l oop. Один из способов реализовать это - использовать std::unordered_map<std::string,T>
с некоторыми вспомогательными данными для индексов. Понятно, что это будет ужасно неэффективно, поскольку для каждого доступа члена вам нужно иметь sh a std::string
.
Моя текущая попытка выглядит следующим образом:
// named-array.h
#pragma once
#include <array>
#include <cstddef>
#define NamedArray_KeyDecl(Name, ...) enum class Name : std::size_t { __VA_ARGS__, NUM }
namespace util {
template <typename K, typename T>
struct NamedArray {
static constexpr std::size_t cast(K k) {
return static_cast<std::size_t>(k);
}
std::array<T,cast(K::NUM)> array;
NamedArray(std::array<T,cast(K::NUM)> a) : array(a) {
}
constexpr T& operator[](K k) {
return array[cast(k)];
}
constexpr T const& operator[](K k) const {
return array[cast(k)];
}
};
}
Что можно использовать как поэтому:
struct Gadget {
int i;
Gadget(int i) : i(i) {}
void operator()() const {
std::cout << "Gadget(" << i << ")\n";
}
};
NamedArray_KeyDecl(Test1, a,b,c,d);
util::NamedArray<Test1,Gadget> gadgets {{0,1,2,3}};
// for each works:
for (auto const& gadget: gadgets.array) {
gadget();
}
// named access works:
gadgets[Test1::b]();
// access by index works:
gadgets.array[1]();
Можно избежать раскрытия элемента массива, перенаправив все функции интерфейса std::array
.
Однако очевидным недостатком является то, что
-
gadgets[Test1::b]
не так хорош, как что-то вроде gadgets.member().b
, а - в заголовочном файле c ++ (который очень вонючий) есть
#define
Есть ли способ иметь именованный массив с такой же производительностью, как у std::array
?