c++11可变编程,如何定义一个向量塔
c++11 variadic programming, how to define a tower of vectors
如何(如果可能的话)使用c++11可变编程来定义函数体中的一系列vector
's,(或者换句话说,一系列N
维数组,N
's递减直到0),如下所示变量?
vector<vector<vector<int>>> v<3>;
vector<vector<int>> v<2>;
vector<int> v<1>;
int v<0>;
我想象的是这样的:
#include <iostream>
#include <vector>
using namespace std;
template<int ...> struct seq {};
template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {};
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
template<int ...S>
void f(seq<S...>) {
//how do I write definitions of v<N> here?
vector<vector<...(N layers)<vector<int> ...> v<N>; //??how-to, not valid c++
vector<vector<...(N -1 layers)<vector<int> ...> v<N-1>;//??how-to, not valid c++
//...
vector<int> v<1>; //??how-to, not valid c++
int v<0>; //??how-to, not valid c++
//...
}
int main() {
f(typename gens<3>);
return 0;
}
同样,这在c++14中会更容易吗?
谢谢,
——编辑——
为了澄清,我所说的"向量塔"最好用n元组(v_1, v_2,…)来描述。, v_N),其中N为整型模板参数。V_1属于向量,v_2属于向量>,以此类推。
——EDIT2
到目前为止,quantdev和R的答案已经成功地解决了为任意固定N(如3)定义N元组的问题,但无法为未指定的N
生成元组。除了答案中的功能外,我还需要一个函数,可以像gen_tower<N>
一样使用,返回tuple(v1,v2,...,vN)
。
考虑使用可变编程来计算阶乘的例子。我需要一个函数来计算任何N
的阶乘factorial<N>()
,以及手动写出任何特定表达式<1*2*3>
的能力。(这就是为什么我问可变编程和c++14
是否会使它更容易的原因。)
纯粹出于个人兴趣,我希望这个序列能够实现一个可以从文件中读取n维数组的泛型函数。我不知道具体是怎么做的,但我认为在第一步,我应该能够定义最终的N
维数组,以及从N-1
到1
的k
的中间k
维数组。我可以读取二维数组和三维数组。但是如果能够读取任意维度的数组就更好了
不需要变量,一个递归的typedef
足以在编译时生成这些类型。
如何实现
1)提供带有2个参数的模板:vector元素类型(T
)和所需的结构维数(size_t N
)。声明一个类型定义type
:它将基于深度为N-1
的模板实例化的type
的声明,因此递归。
template<typename T, size_t N>
struct VectorGenerator
{
typedef std::vector< typename VectorGenerator<T, N-1>::type > type;
};
2)提供结束递归的终止用例,这里是对维度为0的模板的专门化,声明通常的std::vector<T>
类型。
template<typename T>
struct VectorGenerator<T, 0>
{
typedef std::vector<T> type;
};
如何使用
现在可以声明VectorGenerator<T, N>::type
类型的向量v
:
VectorGenerator<double, 4>::type v; // v as a depth of 4 and handle double
但是它不是很好读,也不方便,而且相当冗长。让我们为我们的类型引入新的名称。
这是模板混叠的完美案例,使用(c++ 11) using
关键字进行混叠。我们有两种不同的混叠方式:
1)为特定的维度和类型声明别名,这里我们称其为N=3
和T=double
的V3:
using V3 = VectorGenerator<double, 3>::type; // Alias
V3 v; // Use the alias
或
2)为特定类型声明模板别名,将维度作为模板参数:
template <size_t N>
using V = typename VectorGenerator<double, N>::type; // Alias
V<3> v; // Use the Alias
最终代码示例:
template<typename T, size_t N>
struct VectorGenerator
{
typedef std::vector< typename VectorGenerator<T, N-1>::type > type;
};
template<typename T>
struct VectorGenerator<T, 0>
{
typedef std::vector<T> type;
};
// Alias for V3, V2 ... usage
using V3 = VectorGenerator<double, 3>::type;
using V2 = VectorGenerator<double, 2>::type;
// Alias for V <k> usage
template <size_t N>
using V = typename VectorGenerator<double, N>::type;
int main() {
V<3> v3;
V<2> v2;
v3.push_back(v2);
return 0;
}
指出:
- 考虑Boost多维数组库。
- 我不确定你的最终目标是什么,但这可能是一个过度杀伤。
- 对于您的第二次编辑,声明具有不同维度的多个矢量的
tuple
现在很容易:
例子:
auto tower = std::tuple<V<1>, V<2>, V<3>>(v1, v2, v3);
对于多个"塔"的泛型元组生成,@mpark给出了一个工作的 c++ 14解决方案,我在这里将其改编为我的代码示例:
template <typename T>
struct identity { using type = T; };
// Generate a tuple of towers by mapping index_sequence over gen_tower.
template <typename T, std::size_t... Is>
std::tuple<VectorGenerator<T, Is>...> gen_towers_impl(std::integer_sequence<Is...>);
// Make an index_sequence for N and use gen_towers_impl.
template <typename T, std::size_t N>
struct gen_towers
: identity<decltype(gen_towers_impl<T>(std::make_index_sequence<N>()))> {};
// Convenience type aliases
template <typename T, std::size_t N>
using gen_towers_t = typename gen_towers<T, N>::type;
你需要-std=c++1y
来编译它(包括<utility>
和<tuple>
头文件)
你可以找到一个类似的问题,但处理std::map
在c++ map中的速记语法
这是std::vector
。
#include <iostream>
#include <vector>
template<int N, typename V>
struct NVector { typedef std::vector<typename NVector<N-1, V>::type> type; };
template<typename V>
struct NVector<1, V> { typedef std::vector<V> type; };
int main(int argc, const char *argv[]) {
NVector<1, int>::type v1(10, 0);
NVector<2, int>::type v2;
v2.push_back(v1);
NVector<3, int>::type v3;
v3.push_back(v2);
for ( int i = 0; i < 10; ++i )
{
std::cout << v3[0][0][i] << " ";
}
std::cout << std::endl;
}
输出:<>之前0 0 0 0 0 0 0 0 0之前可以通过using
声明来简化这些向量的使用。
#include <iostream>
#include <vector>
template<int N, typename V>
struct NVector { typedef std::vector<typename NVector<N-1, V>::type> type; };
template<typename V>
struct NVector<1, V> { typedef std::vector<V> type; };
template<int N, typename Val>
using V = typename NVector<N, Val>::type;
int main(int argc, const char *argv[]) {
V<1, int> v1(10, 0);
V<2, int> v2;
v2.push_back(v1);
V<3, int> v3;
v3.push_back(v2);
for ( int i = 0; i < 10; ++i )
{
std::cout << v3[0][0][i] << " ";
}
std::cout << std::endl;
}
如果您想通过假设值类型为int
来简化它,您可以使用:
#include <iostream>
#include <vector>
template<int N, typename V>
struct NVector { typedef std::vector<typename NVector<N-1, V>::type> type; };
template<typename V>
struct NVector<1, V> { typedef std::vector<V> type; };
template<int N>
using V = typename NVector<N, int>::type;
int main(int argc, const char *argv[]) {
V<1> v1(10, 0);
V<2> v2;
v2.push_back(v1);
V<3> v3;
v3.push_back(v2);
for ( int i = 0; i < 10; ++i )
{
std::cout << v3[0][0][i] << " ";
}
std::cout << std::endl;
}
我不会在生成单个塔的过程中讨论太多细节,因为它已经在这里的其他答案中进行了解释。这是我的gen_tower<T, I>
版本,它生成了一个深度为I
的向量塔。
例如,gen_tower_t<int, 2>
为std::vector<std::vector<T>>
。
// Useful for defining meta-functions compactly.
template <typename T>
struct identity { using type = T; };
gen_tower<T,>
// Forward declaration.
template <typename T, std::size_t I>
struct gen_tower;
// Convenience type alias.
template <typename T, std::size_t I>
using gen_tower_t = typename gen_tower<T, I>::type;
// Base case.
template <typename T>
struct gen_tower<T, 0> : identity<T> {};
// Wrap std::vector around tower of depth I - 1.
template <typename T, std::size_t I>
struct gen_tower : identity<std::vector<gen_tower_t<T, I - 1>>> {};
gen_towers<T,>
现在我们可以使用std::index_sequence
来定义N
塔。
// Generate a tuple of towers by mapping index_sequence over gen_tower.
template <typename T, std::size_t... Is>
std::tuple<gen_tower_t<T, Is>...> gen_towers_impl(std::index_sequence<Is...>);
// Make an index_sequence for N and use gen_towers_impl.
template <typename T, std::size_t N>
struct gen_towers
: identity<
decltype(gen_towers_impl<T>(std::make_index_sequence<N>()))> {};
// Convenience type aliases
template <typename T, std::size_t N>
using gen_towers_t = typename gen_towers<T, N>::type;
例子static_assert(std::is_same<gen_tower_t<int, 0>, int>::value, "");
static_assert(std::is_same<
gen_tower_t<int, 2>,
std::vector<std::vector<int>>>::value, "");
static_assert(std::is_same<
gen_towers_t<int, 2>,
std::tuple<int, std::vector<int>>>::value, "");
static_assert(std::is_same<
gen_towers_t<int, 3>,
std::tuple<int,
std::vector<int>,
std::vector<std::vector<int>>>>::value, "");
int main() {}
- 给定一个向量,如何找到该向量的所有子集和的原始索引
- 为什么一个向量上的多线程操作很慢
- 将一个向量插入另一个向量的某个位置
- 将指向给定子类的指针从一个向量复制到另一个向量
- C++ STD 函数运算符:有没有一种方法可以通过函数将一个向量映射到另一个向量上?
- 将向量之间的数字放在另一个向量之间<vector>>如果两个数字的差值为 1
- 如何在不复制的情况下将一个向量移动到另一个向量中
- 使用 std::transform 将向量向量 (a) 添加到另一个向量向量 (b)
- 如何按另一个向量的方向调整一个向量?
- 将字符向量复制到另一个向量
- 制作一对共享指针并推送一个向量
- 你能把一个向量<int64>投射到一个向量<uint8>吗
- 大家好,当一个类有一个向量作为它的数据成员时,为什么它的大小总是24?
- 为什么我们需要在优先级队列声明中添加一个向量作为参数?
- 如何将所有指针从一个向量移动到另一个向量?
- 将一个向量映射到不同的对,即使向量映射到每对时是不同的?
- 生成一个类Name_class并将两种数据类型存储在一个向量中
- 使用步骤c++构建一个向量
- 如何从另一个向量中的另一个第一元素减去向量中的第一元素
- c++11可变编程,如何定义一个向量塔