有没有一种方法可以遍历C ++中对象的不同数据成员

时间:2020-06-11 15:33:48

标签: c++

如果我有一个由3个double组成的类对象; x,y和z,是否可以在函数中循环遍历它们?

例如

for(i in (x,y,z))
    do something;

我可以使用显式强制转换做类似的事情,但是我想知道是否有更优雅的解决方案。

class testc {
public:
    double x, y, z;

    testc(double x, double y, double z)
        :x(x), y(y), z(z)
    {}
};

int main()
{
    testc omega(1, 2, 3);
    cout << *(double*)&omega << " " << *((double*)&omega +1) << " " << *((double*)&omega +2);
}

2 个答案:

答案 0 :(得分:6)

(C ++ 20)遍历已知数量的公共成员:基于范围的for循环初始化语句中的结构化绑定

从C ++ 20开始,我们可以将structured bindingsrange-based for loop初始化语句(后者是C ++ 20的功能)结合在一起:

语法

for( init-statement(可选) 范围声明 range-expression )...

具体来说,在基于范围的for循环中将结构化绑定用作 init-statement

#include <iostream>

class Foo {
public:
    double x, y, z;

    Foo(double x, double y, double z) : x(x), y(y), z(z) {}
};

int main() {
    const Foo foo(1., 2., 3.);

    for (auto [x, y, z] = foo; auto e : {x, y, z}) {
        std::cout << e << " ";
    } // 1 2 3

    return 0;
}

但是,请注意,您只能使用结构化绑定来分解类的公共成员(在您的示例中,所有成员都是公共的)。此外,对于基于范围的for循环的 range-expression 中的初始化程序列表,您可能没有冲突的类型,这意味着此方法仅限于您的示例上下文:其中所有公共成员都属于相同的类型。

为什么使用结构化绑定,而不仅仅是直接对类成员进行列表初始化?

现在,如果您的类的(公共)成员及其实例都有非常简短的名称,我们可能需要考虑省略结构化绑定,而是直接对类成员进行列表初始化:

const Foo f(1., 2., 3.);
for (auto e : {f.x, f.y, f.z}) {
    std::cout << e << " ";
} // 1 2 3

但是,尽管可以说是简短的,但缺点是我们不再从编译器获得任何帮助,无法确定我们是否实际上已完全分解了所有公共成员(不少于,不再更多),当存在时进行检查我们使用结构化绑定:

for (auto [x, y] = foo; auto e : {x, y}) { /* ... */ }
// error: type 'Foo' decomposes into 3 elements, 
//        but only 2 names were provided

for (auto [x, y, z, xx] = foo; auto e : {x, y, z, xx}) { /* ... */ }
// error: type 'Foo' decomposes into 3 elements, 
//        but 4 names were provided

答案 1 :(得分:1)

for (auto&& i : std::vector<double>{x, y, z}){
    // Do something, `i` is the double.
}

是一种方法,但以创建向量为代价。我不相信编译器会将此视作习惯用法并进行优化。

*(&x + 1)这样的代码试图到达y的行为是不确定的。 (指针算术仅在数组内有效。)

您不能为std::arraystd::vectorx使用yz吗?

相关问题