Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 对C++;方式_C++_C_Arrays_Struct_Language Lawyer - Fatal编程技术网

C++ 对C++;方式

C++ 对C++;方式,c++,c,arrays,struct,language-lawyer,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;

这是

的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);
}
结构点{
双x;
双y;
双z;
};
双距离(结构点*p1,结构点*p2){
双d2=0;
双*coord1=&p1->x;
双*coord2=&p2->x;
int i;

对于(i=0;iIMHO,最简单的方法是只实现
操作符[]
。您可以这样创建一个助手数组,或者只创建一个开关

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;
}
结构点
{
双常量和运算符[](标准::大小i)常量
{
常量std::数组坐标{&x,&y,&z};
返回*坐标[i];
}
双重运算符[](标准::大小\u t i)
{
常量std::数组坐标{&x,&y,&z};
返回*坐标[i];
}
双x;
双y;
双z;
};
int main()
{
点p{1,2,3};
std::cout
结构点{
双x;
双y;
双z;
双重运算符[](标准::大小\u t i){
auto self=重新解释(此);
自动v=self+i*sizeof(双精度);
返回*重新解释铸件(v);
}
双常量和运算符[](标准::大小i)常量{
auto self=重新解释(此);
自动v=self+i*sizeof(双精度);
返回*重新解释铸件(v);
}
};
这依赖于`struct中的
double
s之间没有打包。断言这很困难

POD结构是一个字节序列

编译器应该能够将
[]
编译成与原始数组访问或指针算法相同的指令(或缺少这些指令)。可能存在一些问题,这种优化发生得“太晚”,无法进行其他优化,因此请仔细检查对性能敏感的代码


可能转换为
char*
std::byte*
而不是
uintpttr\u t
是有效的,但在这种情况下,如果允许使用指针算法,则大约是有效的。

使用指向成员的指针的constepr数组:

#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);
}
#包括
结构点{
双x;
双y;
双z;
};
双距离(结构点*p1,结构点*p2){
constexpr双点::*coords[3]={&Point::x,&Point::y,&Point::z};
双d2=0;
对于(int i=0;i*coords[i]-p2->*coords[i];
d2+=d*d;
}
返回sqrt(d2);
}

您可以使用这样一个事实:将指针强制转换为
intptr\t
进行算术运算,然后将值强制转换回指针类型,这是实现定义的行为。我相信这在大多数编译器上都会起作用:

template<class T>
T* increment_pointer(T* a){
  return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(a)+sizeof(T));
  }
模板
T*增量_指针(T*a){
返回reinterpret_cast(reinterpret_cast(a)+sizeof(T));
}


这个技术是最有效的,如果使用表查找,优化器似乎不能产生最佳的:

为什么C标签?那么:DWhy,你是被迫这样做的,而不是使用C++特定的或兼容的解决方案?你在你的问题中没有这么说。你没有考虑<代码>双* CODR1=和P1.x;< /代码>问题?没有任何提示。从编译器中删除,不在成员之间添加任何填充,这意味着不能保证coord1[1]是y……因此问题就出现了。在ISO C之前的旧时代,以下代码不会让任何人感到惊讶:也许我不会感到惊讶,但我当时也会称之为废话。[咒骂删除]黑客行为不能被时间所原谅。你所展示的仅仅是成功“工作”的可怕代码不管它本身是什么。它不是一个数组-你为什么要这样对待它?在我看来,最简单的解决方案是首先让
包含一个
数组
,然后使用访问器方法来模拟
x
y
z
。Mmmmmindirection@cmaster:clang为my c提供相同的程序集输出ode和原始的C版本真是一个不错的技巧,它不受可能的填充,同时保持简单的读写,并且不需要对POD结构进行任何更改。这产生了完全相同的结果。@cmaster-这是一个很好的观点。但是在现实世界的实时代码中,你非常关心它的最佳编译,我不明白为什么程序员会这样做不要重新设计类/结构,使其在一开始就没有这个问题。(例如:使其成为一个数组,或一个带有数组的结构或其他东西)在这里,您必须为每个调用动态初始化三个指针,其中一个指针在返回时仅取消引用。最好使用指向成员数组的静态指针。如果它对性能至关重要-是。如果不是,我更喜欢代码简单易读。@Jaa-c如果您希望代码可读,那么使用类模板参数推断。y你认为第二种情况比第一种好吗?在第二种情况下,GCC-7.2@sbabbi这很糟糕,这应该被报告为一个bug吗?我很好奇,标准中允许在
struct
中对
char*
进行指针运算吗?我经常问,如果允许的话,我会得到一个否定的答案。@Oliv:Y您可以始终指向对象内部的指针算术。这是检索当前表示形式的不同字节的方法。@SergeBallesta,令人惊讶的是,标准的这一段定义了数组(或单个对象被视为一个元素的数组)内的指针算术否则,行为是未定义的。你为什么说它是允许的?@Oliv:6.9 Types[basic.Types]说4类型T对象的对象表示是类型T对象使用的N个无符号字符对象的序列,其中N等于sizeof(T)。此外,我的类是可复制的,这意味着它的值可以通过
memcpy
传输,而memcpy仅仅是顺序复制字节。@SergeBallesta正如我在我的问题下面的评论中所说,这不清楚。这是。@SergeBallesta这是没有UB算术指针的解决方案,Yakk使用相同的有问题的UB点呃,算术。虽然我相信它的情况,但更多的是因为
template<class T>
T* increment_pointer(T* a){
  return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(a)+sizeof(T));
  }