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] 是单次函数调用,更容易被编译器内联和优化。

相关推荐
李日灐1 小时前
C++STL: vector 简单使用,讲解
开发语言·c++
明洞日记1 小时前
【VTK手册017】 深入详解 vtkImageMathematics:医学图像的基本算术运算
c++·图像处理·算法·vtk·图形渲染
晚风(●•σ )1 小时前
C++语言程序设计——【算法竞赛常用知识点】
开发语言·c++·算法
程序猿本员1 小时前
8. 定制new和delete
c++
..过云雨1 小时前
14.【Linux系统编程】进程间通信详解(管道通信、System V共享内存、消息队列、信号量)
linux·c语言·c++·后端
Mr_WangAndy1 小时前
C++23新特性_#warning 预处理指令
c++·c++23·c++40周年·c++23新特性·warning预处理命令
ULTRA??1 小时前
C++拷贝构造函数的发生时机,深拷贝实现
开发语言·c++
曦樂~2 小时前
【C++11】引用折叠原理
开发语言·c++
lucky_dog2 小时前
C语言——交换数组元素🍀🍀🍀
c++