【问题标题】:More concise way to declare high dimensional vector更简洁的方式来声明高维向量
【发布时间】:2018-10-25 08:24:55
【问题描述】:

我不喜欢这样调用 3 维向量:

std::vector<std::vector<std::vector<value_type>>>

更不用说我是否想要 4 维甚至更高。

有没有什么方法可以使用模板元编程或某种技术来声明具有更高可读性的高维向量?

例如能够像这样声明一个高维向量(只是一个例子):

t_vector<5, {10, 2, 2, 2, 2}, int> a;

得到一个容量为[10][2][2][2][2]的。

有可能做这样的事情吗? 否则为什么?

【问题讨论】:

  • 您所说的high dimensional vector 是什么意思?你需要什么功能?
  • 我的意思是能够使用用户定义的糖语法(如问题中)为向量声明任意数量的层(在编译期间)。声明容器后,我希望它具有与它对应的功能相同的功能(通过 std::vector)。
  • 我对模板元编程比较陌生。我已经看到 std::tuple 是如何扩展的,因为我没有足够的经验来应用它来为我想要的向量创建糖语法。
  • 如果你想要编译时固定容量,为什么要vector
  • Boost 多维数组库怎么样?

标签: c++ c++11 templates template-meta-programming


【解决方案1】:

从你的例子来看,你需要的是std::array 而不是std::vector,因为后者没有固定的长度。

您可以只使用递归来专门化模板:

template<class T, size_t... Ns> struct foo;

template<class T, size_t N0, size_t... Ns>
struct foo<T, N0, Ns...> {
    using type = std::array<typename foo<T, Ns...>::type, N0>;
};

template<class T>
struct foo<T> {
    using type = T;
};

template<class T, size_t... Ns>
using multiarray_t = typename foo<T, Ns...>::type;

static_assert(
        std::is_same_v<
            multiarray_t<int, 3, 2, 5>,
            std::array<std::array<std::array<int, 5>, 2>, 3>
            >
        );

编辑:

如果你想初始化一个给定大小的std::vector,类似的方法仍然适用:

template<class T, size_t... Ns> struct vec_builder;
template<class T, size_t N0, size_t... Ns>
struct vec_builder<T, N0, Ns...> {
    using type = std::vector<
        typename vec_builder<T, Ns...>::type>;
    static type build() {
        return type(N0, vec_builder<T, Ns...>::build());
    }
};
template<class T>
struct vec_builder<T> {
    using type = T;
    static type build() { return {}; }
};

int main() {
    auto vec = vec_builder<int, 3, 2, 5>::build();
    static_assert(
            std::is_same_v<
            decltype(vec),std::vector<std::vector<std::vector<int>>>
            >);
    assert(vec.size() == 3);
    assert(vec[0].size() == 2);
    assert(vec[1][0].size() == 5);
}

【讨论】:

  • 太棒了!在大多数情况下,这解决了我的问题。但是是否可以将类似的方法应用于 std::vector 并能够在之后动态调整大小?
  • @zetta 是的,有可能,请记住,如果调整向量的大小,可能会使迭代器无效
  • @zetta 如果您动态调整大小,那么在相同维度的元素之间很容易非常导致大小不同。最好将所有内容存储在 1D 向量中,并拥有一系列维度大小
  • 如果我保证不会调整大小,但想将其传递给读取 std::vector 作为其参数的函数,有什么更好的解决方案?
  • @zetta 类似,见编辑。但是如果你想对其进行复杂的操作,最好使用专用的库,比如Eigen
【解决方案2】:

你可以使用 typedef,它只是为一个类型创建一个别名,例如

typedef std::vector<std::vector<std::vector<int>>> iVector3d;

从现在开始,您只需使用 iVector3d 而不是那个又大又丑的东西,当您运行代码时,C++ 会用实际定义替换 iVectord3,所以其他任何东西都不会改变。

这样做的缺点是您必须指定类型,就像我在那里对 int 所做的那样。但优点是与模板相比,它超级易于使用。

【讨论】:

  • template &lt;typename T&gt; using Vector3d = std::vector&lt;std::vector&lt;std::vector&lt;T&gt;&gt;&gt; 是通用的(C++11 起)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-07
  • 2020-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多