重载运算符 () 而不是 [] 用于索引
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 缓存命中率并提高性能。
我正在重构的旧代码库通过重载 ()
运算符而不是 []
运算符来访问 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 typesize_t
这是不正确的。 operator[]
可以接受任何类型的操作数,包括 non-integral 类型。但是,限制是它必须是单个参数。这可能会在未来的标准中改变,但如果你的代码是旧的,它显然会受到影响。
Does this really makes any sense for todays modern compilers and 64bit platforms?
如果您必须存储大量索引并且不需要额外的范围,则在 64 位平台上使用 32 位索引可能会有所帮助。压缩数据不仅可以节省内存,还可以提高 CPU 缓存命中率并提高性能。