遇到一个 c++ 类型推导相关的问题

2023-06-21 14:20:18 +08:00
 Thymolblue

由于其他模块把一个二维数据存成的一维数组, 给我传参时会给我首地址和数据的长宽. 如test1()所示,我可以建一个二维数组的指针去指向数据的头, 并对数据进行操作. 所以我就在想能否写一个函数去完成test1()的工作. 在test2()函数里是时可以完成test1()的工作, 但是返回值并没有达到工作预期. 使用auto result只能访问到数组第一个元素, 使用auto &result无法通过编译.

环境:

在 MSVC 2019 编译器下 test1() 的代码无法通过编译, 会提示数组的边界必须在编译期确定.

问题:

#include <iostream>
#include <vector>

void test1(float *raw, int sizex, int sizey)
{
    using DataType = float[sizex][sizey];
    auto &data = *reinterpret_cast<DataType *>(raw); // 编译通过, 并可以使用迭代器

    // auto &data = *reinterpret_cast<(float *)[sizex][sizey]>(raw);
    // 编译无法通过, 错误如下:
    // error: Expected a type

    for (auto &row: data)
    {
        for (auto &item: row)
        {
            std::cout << item << " ";
        }
        std::cout << std::endl;
    }
    // 输出:
    //     0 1 2 3
    //     4 5 6 7
    //     8 9 10 11
}

template <typename T>
auto test2(T *t, int sizex, int sizey)
{
    using DataType = T[sizex][sizey];
    auto ptr = reinterpret_cast<DataType *>(t);
    return ptr;
}

int main()
{
    int sizex = 3;
    int sizey = 4;
    std::vector<float> vc(sizex * sizey);
    for (int i = 0; i < vc.size(); ++i)
        vc[i] = i;

    test1(vc.data(), sizex, sizey);

    // auto &result = *test2(vc.data(), sizex, sizey);
    // 编译无法通过, 报错如下:
    // In function 'int main()':
    // In function 'int main()':
    // internal compiler error: in expand_expr_real_1, at expr.c:9908
    //      using DataType = T[sizex][sizey];
    //                                      ^

    // auto result = test2(vc.data(), sizex, sizey);
    // 编译可以通过, 但 result 不能向上面一样使用迭代器, debug 下显示 *result 的类型为 float[1][1]

    // auto &result2 = *test2(vc.data(), sizex, sizey);;
    // 编译无法通过, 还是报错 internal compiler error: in expand_expr_real_1, at expr.c:9908

    return 0;
}

634 次点击
所在节点    问与答
6 条回复
inhzus
2023-06-21 14:34:37 +08:00
C-style array 的大小就应该是 constant expression... 不要钻这个牛角尖,不要写 mingw 方言... 不如老老实实就用 (T**, size_x, size_y) 来替代你的 T[size_x][size_y] *
Thymolblue
2023-06-21 14:48:25 +08:00
@inhzus 其他模块给我的就只有数据块头的地址,不是很好更改。其实去计算访问的每个元素的地址也可以,但是如果能把这个指针转成二维数组的话我就可以对数据封装一下,后面的计算会简化很多。
ysc3839
2023-06-21 15:15:59 +08:00
你需要 C++23 的 std::mdspan 。即使不能升级编译器,也有参考实现可以用。
hankai17
2023-06-21 15:19:20 +08:00
constexpr int sizex
Thymolblue
2023-06-21 15:28:30 +08:00
@ysc3839 感谢,本来我是想用 boost::multiarray 的,但是 multiarray 的访问效率太低。如果 std::mdspan 能达到接近直接访问二维数组的速度的话应该就解决问题了。
Thymolblue
2023-06-21 15:29:13 +08:00
@hankai17 传入的数据大小是变化了,没法在编译期确定。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/950632

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX