【发布时间】:2016-07-12 03:49:42
【问题描述】:
tl;dr 是否有任何简单的方法可以将std::get 与非常量索引一起使用?
我知道这个问题已经被问过很多次了,但所提出的解决方案似乎都不是特别简单、雄辩或适合我的情况。
我正在寻找的是:一种使用std::get<E> 的无痛方式,其中E 是任何表达式,以便将T& 返回到已知存在的T(即不受范围异常影响,因此在std::tuple<T> 中绕过安全范围std::get)。
问题似乎是编译器需要知道std::get 的return 的类型,但我将手动输入数据及其类型,不需要确定类型。 (也许auto 可以在某处使用?)
我想这样做的原因可以通过下面的sn-ps来解释。我正在尝试创建一个数据容器类,您可以使用初始化列表来填充它。
-
Point:用于允许元组的模拟初始化器列表。
template<class... T> class Point { public: std::tuple<T...> get() const { return data; } Point(T... t) { data = std::tuple<T...>(t...); } private: std::tuple<T...> data; }; -
数据:设计用于在
std::tuple和std::vector<T>中保存动态数据量,其中T是一组用户定义类型中的每一个。template<typename... T> class Data { public: Data(std::initializer_list<Point<T...>> data = {{}}) : columns(sizeof...(T)) { // ??? } private: byte columns; std::tuple<std::vector<T>...> datas; }; -
结合起来,这应该允许这种简单的格式用于快速数据输入(或未来来自外部源的数据流):
int main() { Data<char, int, float> { { 'A', 1, 3.14 } , { 'B', 2, 6.28 } }; return 0; }
这些旨在稍后被移植到一个充满有用扩展的库中,这些扩展以使非程序员可以轻松输入数据和公式而无需大惊小怪的方式处理数据。公式的一半是有效的,但是由于std::get的限制,我仍然遇到了这一半的问题:
for (auto d : data) {
for (int i = 0; i < columns; ++i) {
std::get<i>(datas).push_back(std::get<i>(data));
// doesn't work; std::get<N> requires const N to know return type to use push_back
}
}
我觉得这真的很令人沮丧,就像大多数人一样。我不能用std::arrays 或std::vectors 替换datas,因为有多种类型;尽管boost::any,我还是想避免使用boost; switch (column) { case 0: std::get<0>(...)... } 可用于模仿动态 std::get,但如果我不能为每个可能的第 n 列手动输入一个案例;仅仅为了这个小目的而对一种新的容器类型进行元编程似乎过于复杂了;并且似乎没有其他快速修复解决方案足以应对这些特殊情况。
【问题讨论】:
-
如果
E直到运行时才知道,那么您希望编译器如何确定get<E>(arg)的类型? -
顺便说一句,C++17 中有
std::any -
为什么要将
columns存储为运行时值?它是sizeof...(T),Data<T...>“知道”。如果您想要“针对元组的每个元素”,甚至“针对元组的每个索引”,这不需要运行时get。据我所知,如果你有一个运行时get<I>,你认为你可以解决一个模糊指定的实际问题。这被称为 XY 问题。您能否完善您的问题以专注于您的实际问题,并包括您尝试的解决方案以及出了什么问题作为细节不是重点? -
@Yakk 添加了更多具体信息。如果不存储
sizeof... (T),我如何计算每个push_back数据中有多少种类型std::vector? -
@carson 类型
Datas和元组都知道它们有多宽。单独存储值没有帮助。