在ISO C之前的日子里,以下代码会让人感到惊讶:
p[i]
不幸的是,这个有问题的行使用指针算法(*(p + i))
按照定义 Undefined Behaviour
在任何数组之外,标准明确不允许。草案4659 for C + +17在8.7 [expr.add]中说:
如果表达式P指向具有n个元素的数组对象x的元素x [i], 表达式P + J和J + P(其中J具有值j)指向(可能是假设的)元素 x [i + j]如果0 <= i + j <= n;否则,行为未定义。
(非规范性)注释86使其更加明确:
为此目的,不是数组元素的对象被认为属于单元素数组。一个 超过n个元素的数组x的最后一个元素的指针被认为等同于指向假设元素的指针 x [n]为此目的。
引用问题的已接受答案使用了C语言通过联合接受类型双关语这一事实,但我无法在C ++标准中找到等效语句。所以我假设包含匿名结构成员和数组的联合将导致C ++中的assert
- 他们 不同的语言......
什么是一种一致的方式来迭代结构的成员,就好像它们是C ++中的数组成员一样?我正在寻找当前(C ++ 17)版本的方法,但也欢迎旧版本的解决方案。
它显然只适用于相同类型的元素,并且可以使用简单的{{1}}检测填充,如其他question所示,因此填充,对齐和混合类型不是我的问题
答案 0 :(得分:24)
使用指向成员指针的constexpr数组:
#include <math.h>
struct Point {
double x;
double y;
double z;
};
double dist(struct Point *p1, struct Point *p2) {
constexpr double Point::* coords[3] = {&Point::x, &Point::y, &Point::z};
double d2 = 0;
for (int i=0; i<3; i++) {
double d = p1->*coords[i] - p2->*coords[i];
d2 += d * d;
}
return sqrt(d2);
}
答案 1 :(得分:17)
恕我直言,最简单的方法就是实施operator[]
。您可以创建一个这样的辅助数组,或者只创建一个开关......
struct Point
{
double const& operator[] (std::size_t i) const
{
const std::array coords {&x, &y, &z};
return *coords[i];
}
double& operator[] (std::size_t i)
{
const std::array coords {&x, &y, &z};
return *coords[i];
}
double x;
double y;
double z;
};
int main()
{
Point p {1, 2, 3};
std::cout << p[2] - p[1];
return 0;
}
答案 2 :(得分:2)
struct Point {
double x;
double y;
double z;
double& operator[]( std::size_t i ) {
auto self = reinterpret_cast<uintptr_t>( this );
auto v = self+i*sizeof(double);
return *reinterpret_cast<double*>(v);
}
double const& operator[]( std::size_t i ) const {
auto self = reinterpret_cast<uintptr_t>( this );
auto v = self+i*sizeof(double);
return *reinterpret_cast<double const*>(v);
}
};
这取决于你的`struct中的double
s之间没有打包。断言这很难。
POD结构是保证的字节序列。
编译器应该能够将[]
编译为与原始数组访问或指针算法相同的指令(或缺少指令)。 可能存在一些问题,其中这种优化发生“太晚”而无法进行其他优化,因此请仔细检查性能敏感代码。
转换为char*
的{{1}}或std::byte*
转换为有效,但there is a core issue关于在这种情况下是否允许指针运算。
答案 3 :(得分:0)
您可以使用这样一个事实,即向intptr_t
执行算术运算,然后将值转换回指针类型实现定义行为。我相信它适用于大多数编译器:
template<class T>
T* increment_pointer(T* a){
return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(a)+sizeof(T));
}
这项技术效率最高,如果查找一个使用表,优化器似乎无法产生最佳效果:assemblies-comparison