我有一个围绕向量和形状的包装结构,如下所示:
template <std::size_t N>
struct array_type {
    std::array<std::size_t, N> shape;
    std::vector<float> data;
};
Run Code Online (Sandbox Code Playgroud)
我想能够构造一个array_type从任何阵列float[N],float[N][M]等等。
目前,我对每个等级都有一个函数,例如
template <std::size_t N>
struct array_type {
    std::array<std::size_t, N> shape;
    std::vector<float> data;
};
Run Code Online (Sandbox Code Playgroud)
我想写一些类似的东西:
template <class Array>
array_type<std::rank_v<Array>> make_array(Array const&);
Run Code Online (Sandbox Code Playgroud)
...但这不适用于初始化列表:
auto arr1 = _1d({1, 2, 3}); // Ok
auto arr2 = make_array({1, 2, 3}); // Ko
Run Code Online (Sandbox Code Playgroud)
有没有办法做到这一点make_array?或者(因为我认为这是不可能的),至少有类似make_array<1>({1, 2, 3})明确指定排名的地方?
array_type::shapestd::extent可以通过一些模板元编程来生成:
template<typename Array, std::size_t... I>
auto extents_impl(const Array& a, std::index_sequence<I...>)
{
    return std::array{std::extent_v<Array, I>...};
}
template<typename Array>
auto extents(const Array& a)
{
    return extents_impl(a, std::make_index_sequence<std::rank_v<Array>>());
}
Run Code Online (Sandbox Code Playgroud)
有了这个,make_array可以写成:
template <class Array, std::enable_if_t<std::is_same_v<std::remove_cv_t<std::remove_all_extents_t<Array>>, float>, int> = 0> // magic incantation :)
array_type<std::rank_v<Array>> make_array(Array const& a)
{
    array_type<std::rank_v<Array>> ret {
        .shape = extents(a),
        .data = std::vector<float>(sizeof a / sizeof(float)),
    };
    std::memcpy(ret.data.data(), &a, sizeof a);
    return ret;
}
Run Code Online (Sandbox Code Playgroud)
我用它memcpy来避免潜在的指针类型别名冲突,以及根据标准的严格解释在 UB 子数组的边界之外进行迭代的技术。
...但这不适用于初始值设定项列表:
添加一个重载:
template <std::size_t N>
array_type<1> make_array(float const (&a)[N])
{
    return make_array<float[N]>(a);
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以在调用中指定数组类型:
make_array<float[2][3]>({{1, 2, 3},{4, 5, 6}});
Run Code Online (Sandbox Code Playgroud)
这不需要重载。
|   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           118 次  |  
        
|   最近记录:  |