【发布时间】:2020-02-20 08:11:38
【问题描述】:
我希望有一种类型既具有命名成员又是可迭代的,因此应该能够通过索引、标签或 for-each 循环来引用成员。实现这一点的一种方法是将std::unordered_map<std::string,T> 与索引的一些辅助数据一起使用。显然,这将是非常低效的,因为对于每个成员访问,您需要散列一个 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 相同的性能?
【问题讨论】:
-
有没有可能——当然有。检查
boost::multi_index的样子。每个索引都有标签类型。我想这是你可能想要的东西 -
@bartop 它看起来更像样板。据我所知,它标记其成员的方式是创建一堆空结构。而且按索引访问似乎很轻量级。
-
我并不是说要使用
multi_index,而只是将其用作示例。无论如何,如果你不想要宏,我认为标签类型是唯一可行的选择
标签: c++ arrays performance named