C++ 创建具有给定大小的n维向量

C++ 创建具有给定大小的n维向量,c++,templates,c++11,variadic-templates,template-meta-programming,C++,Templates,C++11,Variadic Templates,Template Meta Programming,所以,我想要的是创建给定类型的多维向量,其中第一个维度将具有函数调用的第一个参数的大小,等等,例如,如果我这样做的话 std::size_t n = 5; auto x = make_vector<int>(n + 1, n * 2, n * 3); 它似乎适用于1或2个参数,但在3个参数中失败,并出现以下错误(clang++) 包含在/Users/riad/ClionProjects/for jhelper/output/run.cpp文件中:1: /Users/riad/Cli

所以,我想要的是创建给定类型的多维向量,其中第一个维度将具有函数调用的第一个参数的大小,等等,例如,如果我这样做的话

std::size_t n = 5;
auto x = make_vector<int>(n + 1, n * 2, n * 3);
它似乎适用于1或2个参数,但在3个参数中失败,并出现以下错误(clang++)

包含在/Users/riad/ClionProjects/for jhelper/output/run.cpp文件中:1:
/Users/riad/ClionProjects/for jhelper/tasks/TaskC.cpp:12:12:错误:调用“make_vector”时没有匹配函数
自动x=生成向量(n+1,n*2,n*3);
^~~~~~~~~~~~~~~~
/Users/riad/ClionProjects/for jhelper/tasks/。/spcpl/make_vector.hpp:9:6:注意:忽略候选模板:替换失败[with T=int,Args=]:调用函数“make_vector”,该函数在模板定义中既不可见,也无法通过依赖参数的查找找到
自动生成向量(std::size\t first,Args…size)->std::vector{
^                                                                     ~~~~~~~~~~~
/Users/riad/ClionProjects/for jhelper/tasks//spcpl/make_vector.hpp:4:16:注意:候选函数模板不可行:需要单个参数“size”,但提供了3个参数
标准::向量生成向量(标准::大小大小){

如果我理解正确的话,问题是当编译器试图计算make_vector的返回值时,它必须知道参数较少的vector的返回值,但无法做到。我如何解决这个问题?

我通过单独计算类型来实现这一点,但这似乎不必要,尽管它很短

template <typename T, int n>
struct NDVector {
    typedef std::vector<typename NDVector<T, n - 1>::type> type;
};

template <typename T>
struct NDVector<T, 0> {
    typedef T type;
};

template <typename T>
std::vector<T> make_vector(std::size_t size) {
    return std::vector<T>(size);
}


template <typename T, typename... Args>
typename NDVector<T, sizeof...(Args) + 1>::type make_vector(std::size_t first, Args... sizes) {
    typedef typename NDVector<T, sizeof...(Args) + 1>::type Result;
    return Result(first, make_vector<T>(sizes...));
}
模板
结构NDVector{
typedef std::向量类型;
};
模板
结构NDVector{
T型;
};
模板
标准::向量生成向量(标准::大小大小){
返回标准::向量(大小);
}
模板
typename NDVector::type make_vector(std::size_t first,Args…size){
typedef typename NDVector::type结果;
返回结果(首先,生成向量(大小…);
}

将非常欣赏更优雅的解决方案

创建一个名称空间,在其中放置一些助手,称为
详细信息

details
中创建一个类型
struct adl\u helper{};

创建
make_vector
的实现,但其第一个参数始终是名为
Adl
的模板参数。此模板参数从不命名,其实例将传递给递归

通过调用
details::make_vector(details::adl_helper{},blah)
实现
make_vector(blah)


有趣的问题!您遇到的问题是,非限定名称查找将在使用它的范围内查找(按一般性的递增顺序)。但是,从[basic.scope.pdecl]:

名称的声明点紧跟在其完整声明符(第8条)之后,在其完整声明符之前 初始值设定项(如有)

在这个函数中:

template <typename T, typename... Args>
auto make_vector(std::size_t first, Args... sizes) 
-> std::vector<decltype(make_vector<T>(sizes...))> {
    ...
}
在name函数体中,可以进行递归调用,而不会出现任何问题

如果没有C++14,您可以将其转发到一个类模板,该类模板的名称将在所有递归调用的范围内:

template <typename T, size_t N>
struct MakeVector
{
    template <typename... Args>
    static auto make_vector(std::size_t first, Args... sizes)
    -> std::vector<decltype(MakeVector<T, N-1>::make_vector(sizes...))>
    {
        auto inner = MakeVector<T, N-1>::make_vector(sizes...);
        return std::vector<decltype(inner)>(first, inner);        
    }
};

template <typename T>
struct MakeVector<T, 1>
{
    static std::vector<T> make_vector(std::size_t size) {
        return std::vector<T>(size);
    }
};

template <typename T, typename... Args>
auto make_vector(Args... args)
-> decltype(MakeVector<T, sizeof...(Args)>::make_vector(args...))
{
    return MakeVector<T, sizeof...(Args)>::make_vector(args...);
}
模板
结构生成向量
{
模板
静态自动生成向量(std::size\t first,Args…size)
->向量
{
自动内部=生成向量::生成向量(大小;
返回std::vector(第一个,内部);
}
};
模板
结构生成向量
{
静态std::vector生成向量(std::size\u t size){
返回标准::向量(大小);
}
};
模板
自动生成向量(Args…Args)
->decltype(MakeVector::make_vector(args…)
{
返回MakeVector::make_向量(args…);
}

当我发布这篇文章时,我不知道其他答案。如果对某人有用,我不会删除它。当然,启用C++14后,解决方案非常简单

使用[以下代码](您可以实现:

  size_t n = 5;
  auto x = make_vector<int>(n+1, n*2, n*3);
size\u t n=5;
自动x=生成向量(n+1,n*2,n*3);
以下是注释最少的代码:

// Creating a multidimensional container (e.g. `vector`, `map`)
template<template<typename...> class Container,
         typename T,  
         size_t DIMENSION>
struct MultiDimensional
{
  using internal = MultiDimensional<Container, T, DIMENSION-1>;
  using type = Container<typename internal::type>;

  template<typename... Args>
  static
  type Generate (const size_t size, Args... sizes)
  {
    return type(size, internal::Generate(sizes...));
  }
};

// Last dimension overload
template<template<typename...> class Container,
         typename T>
struct MultiDimensional<Container, T, 1>  
{
  using internal = T;
  using type = Container<T>;

  static
  type Generate (const size_t size)
  {
    return type(size);
  }
};

// Wrapper for the specific requirement of creating a multidimensional `std::vector`
template<typename T,
         typename... Args>
auto make_vector(Args... sizes)
 -> typename MultiDimensional<std::vector, T, sizeof...(sizes)>::type
{
  return MultiDimensional<std::vector, T, sizeof...(sizes)>::Generate(sizes...);
}
//创建多维容器(例如`vector`、`map`)
模板
多维结构
{
使用内部=多维;
使用类型=容器;
模板
静止的
类型生成(常量大小、参数…大小)
{
返回类型(大小,内部::生成(大小…);
}
};
//最后维度重载
模板
多维结构
{
使用内部=T;
使用类型=容器;
静止的
类型生成(常量大小\u t大小)
{
返回类型(大小);
}
};
//用于创建多维`std::vector的特定需求的包装器`
模板
自动生成向量(参数…大小)
->typename多维::类型
{
返回多维::生成(大小…);
}

解决这个问题的最简单方法是回到C:

void foo(size_t n) {
    int (*threeDArray)[2*n][3*n] = malloc((n + 1)*sizeof(*threeDArray));

    //Do with your array whatever you like.
    //Here I just initialize it to zeros:
    for(size_t i = 0; i < n + 1; i++) {
        for(size_t j = 0; j < 2*n; j++) {
            for(size_t k = 0; k < 3*n; k++) {
                threeDArray[i][j][k] = 0;
            }
        }
    }

    free(threeDArray);
}
void foo(大小){
int(*threeDArray)[2*n][3*n]=malloc((n+1)*sizeof(*threeDArray));
//你可以随意使用你的阵列。
//在这里,我只是将其初始化为零:
对于(大小i=0;i

正如我所说,C++中不可能这样做:C++标准要求所有的数组大小都是编译时常数。C在这方面更灵活,允许运行C99数组,无论是在代码< TyPulf< /Cord>S.< /P>内,都能运行时数组大小。


因此,当我有一些代码需要认真处理多维数组时,我会认真地问自己,是否值得将这些代码移到纯.c文件中,并将其与我的项目的其余部分链接在一起。

@Columbo,你能不能eleborate?你是否认真考虑过
vector
?如果你需要多维数组,使用一个一维的,并包装它。哦,我不知道,一个大幅度的性能提高?减少不必要的间接?技术上强制的边界一致性?vec
template <typename T, typename... Args>
auto make_vector(std::size_t first, Args... sizes)
{ /* exactly as before */ }
template <typename T, size_t N>
struct MakeVector
{
    template <typename... Args>
    static auto make_vector(std::size_t first, Args... sizes)
    -> std::vector<decltype(MakeVector<T, N-1>::make_vector(sizes...))>
    {
        auto inner = MakeVector<T, N-1>::make_vector(sizes...);
        return std::vector<decltype(inner)>(first, inner);        
    }
};

template <typename T>
struct MakeVector<T, 1>
{
    static std::vector<T> make_vector(std::size_t size) {
        return std::vector<T>(size);
    }
};

template <typename T, typename... Args>
auto make_vector(Args... args)
-> decltype(MakeVector<T, sizeof...(Args)>::make_vector(args...))
{
    return MakeVector<T, sizeof...(Args)>::make_vector(args...);
}
  size_t n = 5;
  auto x = make_vector<int>(n+1, n*2, n*3);
// Creating a multidimensional container (e.g. `vector`, `map`)
template<template<typename...> class Container,
         typename T,  
         size_t DIMENSION>
struct MultiDimensional
{
  using internal = MultiDimensional<Container, T, DIMENSION-1>;
  using type = Container<typename internal::type>;

  template<typename... Args>
  static
  type Generate (const size_t size, Args... sizes)
  {
    return type(size, internal::Generate(sizes...));
  }
};

// Last dimension overload
template<template<typename...> class Container,
         typename T>
struct MultiDimensional<Container, T, 1>  
{
  using internal = T;
  using type = Container<T>;

  static
  type Generate (const size_t size)
  {
    return type(size);
  }
};

// Wrapper for the specific requirement of creating a multidimensional `std::vector`
template<typename T,
         typename... Args>
auto make_vector(Args... sizes)
 -> typename MultiDimensional<std::vector, T, sizeof...(sizes)>::type
{
  return MultiDimensional<std::vector, T, sizeof...(sizes)>::Generate(sizes...);
}
void foo(size_t n) {
    int (*threeDArray)[2*n][3*n] = malloc((n + 1)*sizeof(*threeDArray));

    //Do with your array whatever you like.
    //Here I just initialize it to zeros:
    for(size_t i = 0; i < n + 1; i++) {
        for(size_t j = 0; j < 2*n; j++) {
            for(size_t k = 0; k < 3*n; k++) {
                threeDArray[i][j][k] = 0;
            }
        }
    }

    free(threeDArray);
}