需要对 std::tuple 进行非常量索引访问的雄辩解决方案(即 std::get<E>)
Eloquent solution to needing non-const indexed access of a std::tuple (i.e. std::get<E>)
tl;dr 有什么简单的方法可以将std::get
与非常量索引一起使用吗?
我知道这个问题已经被问过很多次了,但提出的解决方案似乎都不是特别简单、雄辩或适合我的情况。
我正在寻找的是:一种使用std::get<E>
的无痛方式,其中E
是任何表达式,以便将T&
返回到已知存在的T
(即,不受范围异常的影响,因此绕过范围安全std::get
)在std::tuple<T>
中。
问题似乎是编译器需要知道std::get
return
的类型,但我将手动输入数据及其类型,并且不需要确定类型。(也许auto
可以在某个地方使用?
我想要这样做的原因可以通过以下片段来解释。我正在尝试创建一个数据容器类,您可以使用初始值设定项列表来填充该类。
-
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::vector<T>
std::tuple
中保存动态数据量,其中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::array
s 或 std::vector
s 替换数据;尽管boost::any
,我想避免使用boost
; switch (column) { case 0: std::get<0>(...)... }
可以用来模仿动态std::get
,但是如果我不能为每个可能的第 n列手动输入一个案例;仅仅为了这个小目的而对一种新的容器类型进行元编程的努力似乎不必要地过于复杂;似乎没有其他快速解决方案足以应对这些特定情况。
TL;DR 有没有简单的方法可以使用 std::get 与非常量索引?
不,因为甚至没有一种方法可以将其与非常量索引一起使用。既不难也不容易使用。
但是,您可以像这样的构造函数
Data(std::initializer_list<Point<T...>> data)
{
for (auto&& d : data)
{
tup_to_vectup(std::make_index_sequence<sizeof...(T)>{},
datas, d.data);
}
}
有一个像这样的小帮手
template<std::size_t ... I, class VecTup, class Tup>
void tup_to_vectup(std::index_sequence<I...>, VecTup&& vt, Tup&& t)
{
int a[] = {
0, (std::get<I>(vt).push_back(std::get<I>(t)), 0)...
};
(void)a;
}
因为这里实际上不需要非常量索引。类模板参数...T
编译时确定索引。您只需要将它们转换为索引序列并使用它来迭代元组。
template<std::size_t I>
using index_t=std::integral_constant<std::size_t,I>;
template<std::size_t...Is, class F>
void for_each_from_indexes( std::index_sequence<Is...>, F&& f ){
using discard=int[];
(void)discard{0,(void(
f(index_t<Is>{})
),0)...};
}
template<std::size_t N, class F>
void for_each_index( F&& f ){
for_each_from_indexes( std::make_index_sequence<N>{}, std::forward<F>(f) );
}
现在,我们可以在编译时使用一组索引调用 lambda。
template<class...Ts>
void add_data(std::tuple<Ts...> const& data){
for_each_index<sizeof...(Ts)>([&](auto i){
std::get<i>(datas).push_back(std::get<i>(data));
});
}
i
转向索引不是运行时,而是编译时,这里。
需要C++14,但这是2016年。
可能有错别字。
- 运行同一解决方案的另一个项目的项目
- Project Euler问题4的错误解决方案
- 计算每个节点的树高,帮助我解释这个代码解决方案
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- visual c++,如何获取解决方案目录中的代码
- 有没有办法在远程设备上打开和编辑visual Studio 2017解决方案
- C++Matching Brackets 2解决方案不起作用
- 在 ubuntu3 上C++ goto 定义有什么解决方案吗16.04?
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 我的固定时间步长与增量时间和插值的解决方案是错误的吗?
- 无法在问题解决方案中执行输出逻辑
- 最大的回文产品 - 程序未运行,编写解决方案但无法理解问题
- 从预序遍历构造 bst 的 c++ 和 python 解决方案之间的区别
- 使用 stl 排列 std::vector 元素的最短解决方案
- 与 2010 年相比,解决方案更新到 2012 年.std::function = 空错误
- 来自 std::find 的此错误的优雅解决方案是什么
- 为std::function赋值抽象函数——为什么std::ref是一个解决方案
- 派生自库中的std::exception:仅头文件解决方案是否适用于捕获异常
- 需要对 std::tuple 进行非常量索引访问的雄辩解决方案(即 std::get<E>)
- std::map是一个好的解决方案吗