tl; dr 是否有任何简单方法将std::get
与非常量索引一起使用?
我知道这个问题已被多次提出,但所提出的解决方案似乎都不是特别简单,雄辩或适合我的情况。
我正在寻找的是:使用std::get<E>
的无痛方式,其中E
是任何表达式,以便将T&
返回到T
已知存在(即,在范围异常中是安全的,因此绕过std::get
中的范围安全std::tuple<T>
)。
问题似乎是编译器需要知道std::get
的{{1}}的类型,但我将手动输入数据及其类型,而不需要确定这种类型。 (也许return
可以在某个地方使用?)
我想要这样做的原因可以通过以下片段来解释。我正在尝试创建一个数据容器类,您可以使用初始化列表来填充。
Point:用于允许元组的模拟初始化列表。
auto
数据:旨在保存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::array
替换数据;尽管std::vector
,我仍然希望避免使用boost
; boost::any
可用于模仿动态switch (column) { case 0: std::get<0>(...)... }
,但如果我无法为每个可能的 n 列手动输入案例;经过元编程的努力,仅仅为了这个小目的,新的容器类型似乎不必要地过于复杂;似乎没有其他快速解决方案适合这些特殊情况。
答案 0 :(得分:3)
tl; dr 有没有简单的方法将std :: get与非const索引一起使用?
不,因为根本没有一种方法可以将它与非const索引一起使用。既不难也不易使用。
但是你可以使用像
这样的构造函数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;
}
因为你实际上不需要非const索引。您的类模板参数...T
在编译时确定索引。您只需将它们转换为索引序列并使用它来迭代您的元组。
答案 1 :(得分:2)
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年。
可能存在拼写错误。