C++17 如何使用变量模板模仿Julia的'promote_type'函数?

问题描述 投票:0回答:1

由于一些个人原因,我正在开发一个C++版本的Julia's。SparseMatrixCSC 在我移植到C++的项目中,Armadillo的 SpMat 未能成为一个完美的替代品。

template <typename Tv, typename Ti>
struct SparseMatrixCSC
{
    size_t m, n;
    arma::Col<Ti> colptr;
    arma::Col<Ti> rowval;
    arma::Col<Tv> nzval;
};

一些Julia的功能,如 blockdiag() 允许输入一个类似于变数的稀疏矩阵,输出一个 "块状 "矩阵。Julia的脚本代码允许一些通用的方法,这些方法可以很容易地移植到C++17中,比如收集输入中的n-matrix的大小,例如。

template <typename... Args>
constexpr auto blockdiag(const Args& ...args)
{
    auto mX = details::apply([](auto x) { return size(x, 1); }, args...);
    auto nX = details::apply([](auto x) { return size(x, 2); }, args...);
    auto m = sum(mX);
    auto n = sum(nX);
    ...

其中,内部的 details::apply 函数允许递归收集输入的n-矩阵的rowscols。最后的矩阵维数是以 mn. 没问题,代码工作得很好。

但现在,我的问题是如何计算出的 typename 通过收集促进类型的输出矩阵的参数。Tv (价值)和 Ti (索引)从类似功能的东西。从稀疏性矩阵的性质来看 TvTi 类型是数值。而且更具体的是。Ti 是一个积分类型。

据我了解,因为我是一个真正的元编程新手,在最新的C++标准下,最好的方法是使用 <type_traits> std::common_type. 但我不知道如何解包我的变量模板args(包含SparseMatrixCSC),并展开了 std::common_type<...> 参数与获得一个或另一个内部列向量的十类型的漏斗的结果。arma::Col<T>. 类似于:

template <typename Func, typename ... Args>
constexpr auto promote_type(Func f, Args const&... args)
{
    return typename std::common_type<(f(args), ...)>::type;
}

在上一次调用 blockdiag 的功能,由。

typename Tv = details::promote_type([](auto x) { return decltype(x.nzval); }, args...);
typename Ti = details::promote_type([](auto x) { return decltype(x.rowval); }, args...);

不幸的是,太糟糕的是 VS2019 16.5.4 编译器。更多的是,我很确定,折叠表达式 (f(args), ...) 是无效的,不能作为模板参数使用。

所以,我需要你的帮助,我非常感谢你。

EDIT:回答Barry的问题, promote_type 是一个Julia的函数,这样描述。

晋升指的是将混合类型的值转换为单一的公共类型。promote_type 代表了Julia中默认的推广行为,当操作符(通常是数学的)被赋予不同类型的参数时。promote_type 一般尝试返回一个至少可以近似于任一输入类型的大部分值而不会过度扩大的类型。可以容忍一些损失;例如。 promote_type(Int64, Float64) 返回 Float64 尽管严格来说,并非所有 Int64 值可以完全表示为 Float64 值。

julia c++17 sparse-matrix variadic-functions typetraits
1个回答
2
投票

由于每个 args... 这里。

template <typename... Args>
constexpr auto blockdiag(const Args& ...args)

本身就是一个 SparseMatrixCSC,让我们把这一点说得更清楚。

template <typename... T, typename... U>
constexpr auto blockdiag(const SparseMatrixCSC<T, U>& ...args)

这就使我们的要求 blockdiag 更容易理解(现在我们知道需要什么了),也更容易找出答案:我们有了 Ts和 U就在那里,所以就用他们。

template <typename... T, typename... U>
constexpr auto blockdiag(const SparseMatrixCSC<T, U>& ...args)
    -> SpareMatrixCSC<std::common_type_t<T...>, std::common_type_t<U...>>;
© www.soinside.com 2019 - 2024. All rights reserved.