c ++ 11可变编程,如何定义一个向量塔 [英] c++11 variadic programming, how to define a tower of vectors

查看:127
本文介绍了c ++ 11可变编程,如何定义一个向量塔的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何(如果可能)可以使用c ++ 11可变编程在函数体中定义一系列向量'(或换句话说,序列 N 维数组减少 N '直到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>结构人:发型 template< int ... S> struct gens< 0,S ...> {typedef seq< S ...>类型; };

template< int ... S>
void f(seq< S ...>){
//如何写入v< N>这里?
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中更容易吗?



感谢,



- EDIT -



澄清,我的意思是一个塔的矢量最好由一个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 ()手动输出任何特定表达式< 1 * 2 * 3> 。 (这就是为什么我问关于可变参数编程的原因, c ++ 14 是否会更容易。)



PS



纯粹出于个人利益,我希望这个序列可以实现一个可以从文件读取N维数组的通用函数。我不知道究竟是怎么回事,但我认为在第一步,我应该能够定义最终的 N - 三维数组,中间 的三维数组 k N-1 > 1 。我可以读取2维数组和3维数组。

解决方案

不需要可变参数,递归 typedef 足以在编译时生成这些类型。






strong>如何实现?



1)提供一个包含两个参数的模板:向量元素类型$ c> T )和结构所需的维度( size_t N )。声明一个typedef 类型:它将基于对类型的声明$ c> N-1 ,因此递归。

  template< typename T,size_t N& 
struct VectorGenerator
{
typedef std :: vector< typename VectorGenerator< T,N-1> :: type>类型;
};

2)提供终止递归的终止案例,我们的模板的尺寸为0,声明一个通常的 std :: vector< T> 的类型。

  template< typename T> 
struct VectorGenerator< T,0>
{
typedef std :: vector< T>类型;
};






如何使用? strong>



我们现在可以声明一个 v 类型 VectorGenerator< T,N& ; :: type

  VectorGenerator< double,4& // v as a depth of 4 and handle double 

但它不是很可读或方便,详细。让我们为我们的类型引入新的名称。



这是模板别名,使用(C ++ 11)使用关键字进行别名。我们有两种不同的锯齿方法:



1)声明特定维度和类型的别名, c $ c> N = 3 T = double

  using V3 = VectorGenerator< double,3> :: type; // Alias 

V3 v; // Use the alias

或者,



2)为特定类型声明模板别名,将尺寸保留为模板参数:

  template< size_t N> 
使用V = typename VectorGenerator< double,N> :: type; // Alias

V< 3> v; //使用别名






示例:

  template< typename T,size_t N& 
struct VectorGenerator
{
typedef std :: vector< typename VectorGenerator< T,N-1> :: type>类型;
};

template< typename T>
struct VectorGenerator< T,0>
{
typedef std :: vector< T>类型;
};

// V3,V2的别名...用法
使用V3 = VectorGenerator< double,3> :: type;
使用V2 = VectorGenerator< double,2> :: type;

// V< k>的别名用法
template< size_t N>
使用V = typename VectorGenerator< double,N> :: type;

int main(){

V< 3> v3;
V 2 v2;
v3.push_back(v2);
return 0;
}









  • 请考虑复制多维数组库

  • 我不知道你的最终目标是什么,但这可能是一个过分。 / li>
  • 对于您的第二次修改,现在可以轻松地声明具有多个不同尺寸向量的元组



示例:

  = std :: tuple< V 1,V 2,V 3>(v1,v2,v3); 

对于多个塔的通用元组生成,@mpark给出了工作 C ++ 14 解决方案,我将其适用于我的代码示例:

  template< typename T> 
struct identity {using type = T; };

//通过将index_sequence映射到gen_tower来生成塔的元组。
template< typename T,std :: size_t ... Is>
std :: tuple< VectorGenerator< T,Is> ...> gen_towers_impl(std :: integer_sequence< Is ...>);

//为N创建一个index_sequence并使用gen_towers_impl。
template< typename T,std :: size_t N>
struct gen_towers
:identity< decltype(gen_towers_impl< T>(std :: make_index_sequence< N>())) {};

//便利类型别名
模板< typename T,std :: size_t N>
using gen_towers_t = typename gen_towers< T,N> :: type;

您将需要 -std = c ++ 1y 编译它(并包含< utility> < tuple> headers)



请参阅此处的工作示例。


How (if possible) can I use c++11 variadic programming to define a series of vector's in a function body, (or in other words, a sequence of N-dimensional arrays with decreasing N's until 0), like the variables below?

vector<vector<vector<int>>> v<3>;
vector<vector<int>> v<2>;
vector<int> v<1>;
int v<0>;

What I imagined is something like:

#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;
}

Also, would this be easier in c++14?

Thanks,

--EDIT--

Just to clarify, what I mean by "a tower of vectors" is best described by a N-tuple (v_1, v_2, ..., v_N), where N is an integral template parameter. v_1 is of vector, v_2 is of vector>, and so on.

--EDIT2--

So far, quantdev and R's answers have successfully solved the problem of defining a N-tuple for any fixed N, like 3, but cannot generate a tuple for an unspecified N. In addition to the functionality in the answers, I need a function which can be used like gen_tower<N> that returns tuple(v1,v2,...,vN).

Consider the example of using variadic programming to compute factorials. I need a function to compute factorial factorial<N>() for any N, in addition to the ability to write out any specific expression <1*2*3> manually. (That was the reason why I asked about variadic programming and whether c++14 will make it easier.)

P.S.

Purely out of personal interests, I want this sequence to hopefully implement a generic function that can read a N-dimensional array from file. I don't know exactly how yet, but I think at step one, I should be able to define the final N-dimensional array, and the intermediate k-dimensional arrays for k from N-1 to 1. I can read 2-dimensional arrays, and 3-dimensionals. But it would be nice to be able to read arrays of any dimensions.

解决方案

There is no need for variadics, a recursive typedef is sufficient to generate those types at compile time.


How is is implemented ?

1) Provide a template with 2 arguments : the vector elements type (T), and the desired dimension of the structure (size_t N). Declare a typedef type : it will be based on the declaration of type for the template instantiated with the depth N-1, hence the recursion.

template<typename T, size_t N>
struct VectorGenerator
{
    typedef std::vector< typename VectorGenerator<T, N-1>::type > type;
};

2) Provide a termination case for ending the recursion, here a specialization of our template with the dimension 0, declaring the type of a usual std::vector<T>.

template<typename T>
struct VectorGenerator<T, 0>
{
    typedef std::vector<T> type;
};


How to use it ?

We can now declare a vector v of type VectorGenerator<T, N>::type :

VectorGenerator<double, 4>::type v; // v as a depth of 4 and handle double

But it's not very readable or convenient, and pretty verbose. Let's introduce new names for our types.

This is the perfect case for template aliasing, with the (C++11) using keyword for aliasing. We have 2 different ways of aliasing :

1) Declare an alias for a particular dimension and type, here we call it V3 for N=3 and T=double :

using V3 = VectorGenerator<double, 3>::type;  // Alias

V3 v;                                         // Use the alias

Or,

2) Declare a template alias for a particular type, leaving the dimension as a template parameter:

template <size_t N> 
using V = typename VectorGenerator<double, N>::type;  // Alias

V<3> v;                                              // Use the Alias


Final code sample:

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;
}


Notes :

  • Consider the Boost MultiDimensional Array library.
  • I am not sure of what your final goal is, but this might well be an overkill.
  • As for your second edit, declaring a tuple with multiple vectors of different dimensions is now easy :

Example:

auto tower = std::tuple<V<1>, V<2>, V<3>>(v1, v2, v3);

For the generic tuple generation of multiple "towers", @mpark gave a working C++14 solution, I adapt it here to my code sample:

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;

You will need -std=c++1y to compile it (and include <utility> and <tuple> headers)

See a working example here.

这篇关于c ++ 11可变编程,如何定义一个向量塔的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆