C++23新特性_多维下标运算符

文章目录

本文讲解C++23新特性之多维下标运算符

第一章 C++23语言特性

1.3 多维下标运算符

在C++20之前,如果想写一个二维矩阵的元素,通常又以下两种实现方式。

方式1:函数调用风格matrix(x, y)。显示方式是 重载 operator()。缺点是,()这表示一个函数调用,而[] 才代表 访问数据,这不够直观。

方式2:链式下标风格maxtrix[x][y]. 重载 operator[] 返回一个代理对象(Proxy Object),该代理对象再重载 operator[]。这种实现方式需要维护临时对象,难以优化,容易产生性能开销。

C++23 的解决方案: 直接允许 operator[] 像 operator() 一样,接受多个参数。直接使用 matrix[x, y] 这种代码即可实现矩阵元素的访问。

1.3.1 语法格式

语法非常简单,没有任何新关键字,只是放宽了对 operator[] 参数个数的检查。

cpp 复制代码
    struct MyGrid 
    {
        std::vector<int> data;
        size_t width;

        // C++23 之前:operator[] 只能有一个参数
        int & operator[](size_t indices)
        {
            return data[indices];
		}

        // C++23 :合法!
        int& operator[](size_t x, size_t y)
        {
            return data[y * width + x];
        }

        // 支持变长参数模板
        template<typename... Args>
        int& operator[](Args... indices) 
        {
            // 计算多维偏移量 
        }
    };
    void test()
    {
		MyGrid grid;
        grid[2, 3] = 33;
    }

注意在MSVC中需要设置编译器支持:最新 C++ 工作草案中的功能 (/std:c++latest).

1.3.2 举例实现

示例1:基础二维数组实现

实现方式如下:

cpp 复制代码
    class Matrix2D
    {
    public:
        Matrix2D(size_t r, size_t c)
            : rows(r)
            , cols(c)
            , data(r* c)
        {

        }
        // C++23 多维度下的重载
        double& operator[](size_t row, size_t col)
        {
            return data[row * cols + col];
        }

        // const版本 
        const double& operator[](size_t row, size_t col) const
        {
            return data[row * cols + col];
        }

    private:
        std::vector<double> data;
        size_t rows, cols;
    };

    void test()
    {
        Matrix2D mat(4, 4);
        mat[1, 2] = 3.14;
		std::cout << "mat[1,2]: " << mat[1, 2] << std::endl;
    }

这在最新的vs2026下编译不过,还不支持这样的实现方式。

示例2:变长参数(N维张量)

结合变长模板参数(Variadic Templates),我们可以创建一个支持任意维度的张量类。

实现了一个类似python中的张量。

cpp 复制代码
    template<size_t N>
    struct Tensor
    {
    private:
        std::array<size_t, N> shape_;   // 存储每个维度的尺寸,例如 {2, 3, 4}
        std::array<size_t, N> strides_; // 存储每个维度的步长
        std::vector<int> data_;      // 存储数据的一维数组

        // 辅助函数,用于计算一维索引
        template<typename... Args>
        size_t get_index(size_t i, Args... rest) const
        {
            // 递归计算:当前维度的索引 * 当前维度的步长 + 剩余维度的计算结果
            constexpr size_t dim = N - sizeof...(rest) - 1;
            return shape_[dim] > i ? (i * strides_[dim] + get_index(rest...)) : 0;
        }

        // 递归基例:最后一个维度
        size_t get_index(size_t i) const
        {
            constexpr size_t dim = N - 1;
            return shape_[dim] > i ? i * strides_[dim] : 0;
        }

    public:
        // 构造函数,接收每个维度的尺寸
        template<typename... Dims>
        Tensor(Dims... dims) : shape_{ static_cast<size_t>(dims)... }
        {
            static_assert(sizeof...(Dims) == N, "Initializer list does not match number of dimensions");

            size_t total_size = 1;
            // 从后向前计算步长和总大小
            for (int i = N - 1; i >= 0; --i)
            {
                strides_[i] = total_size;
                total_size *= shape_[i];
            }
            data_.resize(total_size);
        }

        // C++23 多维下标运算符
        template<typename... Args>
        int& operator[](Args... indices)
        {
            static_assert(sizeof...(Args) == N, "Wrong number of dimensions for subscript");
            return data_[get_index(indices...)];
        }

        // const 版本
        template<typename... Args>
        const int& operator[](Args... indices) const
        {
            static_assert(sizeof...(Args) == N, "Wrong number of dimensions for subscript");
            return data_[get_index(indices...)];
        }
    };

    void test()
    {
        // 创建一个 2x3x4 的三维张量
        Tensor<3> t(2, 3, 4);

        // 赋值
        t[1, 2, 3] = 42;
        t[0, 1, 2] = 100;

        // 读取
        std::cout << "t[1, 2, 3] = " << t[1, 2, 3] << std::endl;
        std::cout << "t[0, 1, 2] = " << t[0, 1, 2] << std::endl;

        // 尝试使用错误的维度数量,会触发 static_assert 编译错误
        // t[0, 0] = 1; // 错误: "Wrong number of dimensions for subscript"
    }

1.3.3总结

C++23支持的多维度下标,相比 [][] 的代理对象模式,[x, y] 是单次函数调用,更容易被编译器内联和优化。

相关推荐
Morwit7 小时前
【力扣hot100】64. 最小路径和
c++·算法·leetcode
OliverH-yishuihan8 小时前
开发linux项目-在 Windows 上 基于“适用于 Linux 的 Windows 子系统(WSL)”
linux·c++·windows
七禾页丫8 小时前
面试记录12 中级c++开发工程师
c++·面试·职场和发展
zmzb01039 小时前
C++课后习题训练记录Day56
开发语言·c++
编程小Y9 小时前
C++ Insights
开发语言·c++
王老师青少年编程10 小时前
csp信奥赛C++标准模板库STL案例应用5
c++·stl·set·集合·标准模板库·csp·信奥赛
历程里程碑10 小时前
hot 206
java·开发语言·数据结构·c++·python·算法·排序算法
Tipriest_10 小时前
C++ 的 ranges 和 Python 的 bisect 在二分查找中的应用与实现
c++·python·算法·二分法
誰能久伴不乏11 小时前
epoll 学习踩坑:`fcntl` 设置非阻塞到底用 `F_SETFL` 还是 `F_SETFD`?
linux·服务器·网络·c++·tcp/ip
杨忆11 小时前
构建自己的开发工作台MFC
数据库·c++·mfc