重载运算符 () 而不是 [] 用于索引

Overloading operator () instead of [] for indexing

我正在重构的旧代码库通过重载 () 运算符而不是 [] 运算符来访问 n 维向量的方式非常不正统。

为了说明,假设 Vec 是一个 class 重载两个运算符以用于内部双精度列表的索引目的。

Vec v, w;
int index = 651;
double x = v(index);   // they index like this ..
double y = w[index];   // .. instead of like normally..

我只能想到你这样做的一个很好的理由:operator[] 需要一个类型为 size_t 的参数,它可能是也可能不是 uint64,具体取决于平台.另一方面,代码中使用的索引类型主要是 int,这意味着索引时会进行大量 implicit/explicit 类型转换。该代码的索引非常繁重,所以我很犹豫是否要更改它。

这对当今的现代编译器和 64 位平台真的有意义吗?我很快在 https://godbolt.org/ You can try it out here here

上进行了测试

我主要关注最新的 x64 gcc 和 Visual Studio 编译器,但在 x86-64 gcc (11.2) 中编译时会出现差异。 gcc为()运算符添加了一条cdqe指令,我们知道可能是.

我有点纳闷。为什么会做出这样的选择?

更新

如答案中所述,我关于 operator [] 被锁定为 size_t 类型大小的假设是不正确的。如果您使用 int 而不是 uint64 索引进行索引,则编译后的代码几乎相同,只是使用了不同的寄存器和常量。

使用 () 为多个维度提供多个索引的想法非常好,我必须说。实际上并没有在代码库中的任何地方使用,所以我认为最好用 [] 替换它。我也很高兴看到它在未来的 C++ 版本中由适当的索引运算符处理。

[] 的一个“问题”是当您有多个维度时。使用数组,您可以执行 arr[val1][val2],而 arr[val1] 将为您提供一个数组,您可以使用 [val2] 进行索引。对于 class 类型,这并不那么简单。没有 [][] 运算符,因此 [val1] 需要 return 可以应用 [val2] 的对象。这意味着您需要创建另一种类型并提供您想要的所有功能。使用 (),您可以执行 data(val1, val2) 并且不需要中间对象。

The operator[] requires an argument of type size_t

这是不正确的。 operator[] 可以接受任何类型的操作数,包括 non-integral 类型。但是,限制是它必须是单个参数。这可能会在未来的标准中改变,但如果你的代码是旧的,它显然会受到影响。

Does this really makes any sense for todays modern compilers and 64bit platforms?

如果您必须存储大量索引并且不需要额外的范围,则在 64 位平台上使用 32 位索引可能会有所帮助。压缩数据不仅可以节省内存,还可以提高 CPU 缓存命中率并提高性能。