别名结构和数组C++方式

Ser*_*sta 28 c c++ arrays struct language-lawyer

这是我的另一个问题的 C++后续

在ISO C之前的旧时代,以下代码会让人感到惊讶:

struct Point {
    double x;
    double y;
    double z;
};
double dist(struct Point *p1, struct Point *p2) {
    double d2 = 0;
    double *coord1 = &p1->x;
    double *coord2 = &p2->x;
    int i;
    for (i=0; i<3; i++) {
        double d = coord2[i]  - coord1[i];    // THE problem
        d2 += d * d;
    }
    return sqrt(d2);
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这个问题的行使用指针算法(p[i]定义 *(p + i)).其明确地不是由标准允许的任何阵列的外面草案4659用于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++标准中找到等价物.所以我假设一个包含匿名结构成员和数组的联合将导致Undefined BehaviourC++ - 它们不同的语言......

题:

什么是一种一致的方式来迭代结构的成员,就好像它们是C++中的数组成员一样?我正在寻找当前(C++ 17)版本的方法,但也欢迎旧版本的解决方案.

免责声明:

它显然只适用于相同类型的元素,并且可以通过简单检测填充assert,如其他问题所示,因此填充,对齐和混合类型不是我的问题.

Tob*_*obi 25

使用指向成员的指针的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);
}
Run Code Online (Sandbox Code Playgroud)

  • @cmaster - 这是一个很好的观点.但是在真实世界的实时代码中,你关心它的**很多关于它的最佳编译,我不明白为什么编码器不会重新设计类/结构而不是首先没有这个问题.(例如:使它成为一个数组,或带有数组或其他东西的结构) (2认同)

Jaa*_*a-c 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 是什么让你认为第二种情况比第一种情况好?在第二种情况下,GCC-7.2 [无法消除`coords`上的额外负载](https://godbolt.org/g/XpdTvQ) (4认同)