V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
Thymolblue
V2EX  ›  问与答

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

  •  
  •   Thymolblue · 2023-06-21 14:20:18 +08:00 · 626 次点击
    这是一个创建于 550 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    环境:

    • MinGW64 7.3.0, Qt 5.12.12
    • MinGW64 11.2.0, Qt 6.5.2
    • C++ 17
    • Windows 10

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

    问题:

    • test1()中算是运行期间创建了一个类型吗?
    • 是否可能用函数实现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;
    }
    
    
    6 条回复    2023-06-21 15:29:13 +08:00
    inhzus
        1
    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
        2
    Thymolblue  
    OP
       2023-06-21 14:48:25 +08:00
    @inhzus 其他模块给我的就只有数据块头的地址,不是很好更改。其实去计算访问的每个元素的地址也可以,但是如果能把这个指针转成二维数组的话我就可以对数据封装一下,后面的计算会简化很多。
    ysc3839
        3
    ysc3839  
       2023-06-21 15:15:59 +08:00 via Android   ❤️ 1
    你需要 C++23 的 std::mdspan 。即使不能升级编译器,也有参考实现可以用。
    hankai17
        4
    hankai17  
       2023-06-21 15:19:20 +08:00
    constexpr int sizex
    Thymolblue
        5
    Thymolblue  
    OP
       2023-06-21 15:28:30 +08:00 via Android
    @ysc3839 感谢,本来我是想用 boost::multiarray 的,但是 multiarray 的访问效率太低。如果 std::mdspan 能达到接近直接访问二维数组的速度的话应该就解决问题了。
    Thymolblue
        6
    Thymolblue  
    OP
       2023-06-21 15:29:13 +08:00 via Android
    @hankai17 传入的数据大小是变化了,没法在编译期确定。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1104 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 23:36 · PVG 07:36 · LAX 15:36 · JFK 18:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.