C++17 如何使用可变参数模板模仿 Julia 的 'promote_type' 函数
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' 矩阵。 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
函数允许递归收集输入 n 矩阵上的 rows/cols。最终的矩阵维度在 m
和 n
中求和。没问题,代码完美运行。
但是现在,我的问题是通过 collecting/promoting 类型 Tv
(值)和 Ti
(索引)来计算输出矩阵的 typename
参数类似功能的东西。根据稀疏矩阵的性质,Tv
和 Ti
类型是数值。更具体地说,Ti
是一个整型。
据我所知,因为我是使用最新 C++ 标准进行元编程的真正新手,所以最好的方法是使用 <type_traits> std::common_type
。但是我看不到如何解压缩可变参数模板参数(包含 SparseMatrixCSC)并使用获得一个或另一个内部列向量的 decltype arma::Col<T>
的仿函数的结果来扩展 std::common_type<...>
参数.像 :
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), ...)
无效,不能用作模板参数。
所以,我需要你的帮助,我非常感谢你。
编辑:
为了回答巴里,promote_type
是一个 Julia 的函数,描述如下:
Promotion refers to converting values of mixed types to a single
common type. promote_type
represents the default promotion behavior in
Julia when operators (usually mathematical) are given arguments of
differing types. promote_type
generally tries to return a type which
can at least approximate most values of either input type without
excessively widening. Some loss is tolerated; for example,
promote_type(Int64, Float64)
returns Float64
even though strictly, not
all Int64
values can be represented exactly as Float64
values.
因为每个 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
的要求更容易理解(现在我们知道它需要什么),也更容易找出答案:我们有 T
和 U
就在那里,所以只需使用'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...>>;
出于某些个人原因,我正在开发 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' 矩阵。 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
函数允许递归收集输入 n 矩阵上的 rows/cols。最终的矩阵维度在 m
和 n
中求和。没问题,代码完美运行。
但是现在,我的问题是通过 collecting/promoting 类型 Tv
(值)和 Ti
(索引)来计算输出矩阵的 typename
参数类似功能的东西。根据稀疏矩阵的性质,Tv
和 Ti
类型是数值。更具体地说,Ti
是一个整型。
据我所知,因为我是使用最新 C++ 标准进行元编程的真正新手,所以最好的方法是使用 <type_traits> std::common_type
。但是我看不到如何解压缩可变参数模板参数(包含 SparseMatrixCSC)并使用获得一个或另一个内部列向量的 decltype arma::Col<T>
的仿函数的结果来扩展 std::common_type<...>
参数.像 :
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), ...)
无效,不能用作模板参数。
所以,我需要你的帮助,我非常感谢你。
编辑:
为了回答巴里,promote_type
是一个 Julia 的函数,描述如下:
Promotion refers to converting values of mixed types to a single common type.
promote_type
represents the default promotion behavior in Julia when operators (usually mathematical) are given arguments of differing types.promote_type
generally tries to return a type which can at least approximate most values of either input type without excessively widening. Some loss is tolerated; for example,promote_type(Int64, Float64)
returnsFloat64
even though strictly, not allInt64
values can be represented exactly asFloat64
values.
因为每个 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
的要求更容易理解(现在我们知道它需要什么),也更容易找出答案:我们有 T
和 U
就在那里,所以只需使用'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...>>;