tin*_*lyx 15 c++ templates metaprogramming c++11 c++14
如何(如果可能的话)我可以使用c ++ 11可变参数编程来定义vector函数体中的一系列函数(或者换句话说,一个N具有递减N的s 的序列直到0),如下面的变量?
vector<vector<vector<int>>> v<3>;
vector<vector<int>> v<2>;
vector<int> v<1>;
int v<0>;
Run Code Online (Sandbox Code Playgroud)
我想象的是:
#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;
}
Run Code Online (Sandbox Code Playgroud)
另外,在c ++ 14中这会更容易吗?
谢谢,
- 编辑 -
只是为了澄清,"向量塔"的意思最好用N元组(v_1,v_2,...,v_N)来描述,其中N是一个整数模板参数.v_1是向量,v_2是向量>,依此类推.
--EDIT2--
到目前为止,quantdev和R的答案已成功解决了为任何固定N定义N元组的问题,如3,但不能为未指定的元素生成元组N.除了答案中的功能之外,我还需要一个可以像gen_tower<N>返回一样使用的函数tuple(v1,v2,...,vN).
考虑使用可变参数编程来计算阶乘的示例.除了能够手动写出任何特定表达式之外,我还需要一个函数来计算factorial<N>()任何因子.(这就是为什么我询问可变参数编程以及是否会使它变得更容易的原因.)N<1*2*3>c++14
PS
纯粹出于个人兴趣,我希望这个序列有希望实现一个可以从文件中读取N维数组的通用函数.我不知道究竟如何,但我觉得在步骤之一,我应该能够确定最终的N维数组,中间k维数组为k从N-1到1.我可以阅读二维数组和三维数据.但是能够读取任何维度的数组会很好.
qua*_*dev 25
不需要变量,递归typedef就足以在编译时生成这些类型.
如何实施?
1)提供一个带有2个参数的模板:向量元素type(T)和结构所需的维度(size_t N).声明一个typedef type:它将基于type用深度实例化的模板的声明N-1,因此递归.
template<typename T, size_t N>
struct VectorGenerator
{
typedef std::vector< typename VectorGenerator<T, N-1>::type > type;
};
Run Code Online (Sandbox Code Playgroud)
2)提供一个终止递归的终止案例,这里是我们的模板的特化,其中维度为0,声明了通常的类型std::vector<T>.
template<typename T>
struct VectorGenerator<T, 0>
{
typedef std::vector<T> type;
};
Run Code Online (Sandbox Code Playgroud)
如何使用它 ?
我们现在可以声明一个v类型的向量VectorGenerator<T, N>::type:
VectorGenerator<double, 4>::type v; // v as a depth of 4 and handle double
Run Code Online (Sandbox Code Playgroud)
但它不是非常易读或方便,而且非常冗长.让我们为我们的类型引入新名称.
这是模板别名的完美案例,使用(C++ 11)using关键字进行别名.我们有两种不同的别名方法:
1)声明特定维度和类型的别名,这里我们将其称为V3 for N=3和T=double:
using V3 = VectorGenerator<double, 3>::type; // Alias
V3 v; // Use the alias
Run Code Online (Sandbox Code Playgroud)
要么,
2)声明特定类型的模板别名,将维度保留为模板参数:
template <size_t N>
using V = typename VectorGenerator<double, N>::type; // Alias
V<3> v; // Use the Alias
Run Code Online (Sandbox Code Playgroud)
最终代码示例:
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;
}
Run Code Online (Sandbox Code Playgroud)
备注:
tuple现在可以轻松地声明具有不同尺寸的多个矢量:例:
auto tower = std::tuple<V<1>, V<2>, V<3>>(v1, v2, v3);
Run Code Online (Sandbox Code Playgroud)
对于多个"塔"的通用元组生成,@ 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;
Run Code Online (Sandbox Code Playgroud)
你需要-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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
0 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;
}
Run Code Online (Sandbox Code Playgroud)
如果您想通过假设值类型使其仍然简化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;
}
Run Code Online (Sandbox Code Playgroud)