繁体   English   中英

C++17 如何使用可变参数模板模仿 Julia 的“promote_type” function

[英]C++17 How to mimic Julia's 'promote_type' function using variadic template

由于某些个人原因,我正在研究 Julia 的SparseMatrixCSC的 C++ 版本,该版本在我移植到 C++ 的项目中是特定的,而犰狳的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 blockdiag()允许输入中的稀疏矩阵的可变参数数量和 output 中的一个“blockdiag”矩阵。 Julia 的脚本代码允许使用 C++17 轻松移植的一些通用方法,例如收集输入中 n 矩阵的大小,例如:

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 function 允许递归地收集输入 n 矩阵上的行/列。 最终的矩阵维度在mn中求和。 没问题,代码完美运行。

但是现在,我的问题是通过从类似typename中收集/提升类型Tv (值)和Ti (索引)来计算输出矩阵的类型名参数。 由于稀疏矩阵的性质, TvTi类型是数值。 更具体地说, Ti是一个整数类型。

据我了解,因为我是使用最新标准 C++ 进行元编程的真正新手,所以最好的方法是使用<type_traits> std::common_type 但是我看不到如何解压缩我的可变参数模板 args(包含 SparseMatrixCSC)并使用获取一个或另一个内部列向量arma::Col<T>的 decltype 的函子的结果扩展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 function 中调用:

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), ...)是无效的,不能用作模板参数。

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

编辑:回答巴里, promote_type是 Julia 的 function 描述如下:

提升是指将混合类型的值转换为单一的通用类型。 当运算符(通常是数学)被赋予不同类型的 arguments 时, promote_type表示 Julia 中的默认提升行为。 promote_type类型通常会尝试返回一个类型,该类型至少可以近似任一输入类型的大多数值而不会过度扩展。 有些损失是可以容忍的; 例如, promote_type(Int64, Float64)返回Float64 ,尽管严格来说,并非所有Int64值都可以完全表示为Float64值。

由于每个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的要求更容易理解(现在我们知道它需要什么),也更容易找出答案:我们在那里有TU ,所以只需使用 'em:

template <typename... T, typename... U>
constexpr auto blockdiag(const SparseMatrixCSC<T, U>& ...args)
    -> SpareMatrixCSC<std::common_type_t<T...>, std::common_type_t<U...>>;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM