如何在C++中迭代类的变量成员

5
我目前正在尝试对一些数据进行复杂的变量校正(基于在各种相空间进行归一化),这需要对大量变量进行操作。由于每个校正都遵循相同的过程,我想知道是否有途径可以迭代地完成这个任务,而不是逐个处理每个变量(因为我需要对约18-20个变量执行此操作)。C ++ 能够处理这个问题吗?有人告诉我要用Python尝试,但我觉得有可能用C ++ 来完成... 我卡壳了!
举个例子,给出以下类似数据:
class VariableClass{
    public :
      //each object of this class represents an event for this particlular data set 
      //containing the following variables
      double x;
      double y;
      double z;
}

我想做类似以下的事情:
for (int i=0; i < num_variables; i++)
{
   for (int j=0; j < num_events; j++)
   {
     //iterate through events
   }
   //correct variable here, then move on to next one
}

非常感谢您提前给予的任何建议!!!


2
你的意思是像一个数组吗? - chris
2
这是一个有趣的问题。我很好奇你会得到什么样的回答。我不禁想知道你是否会遇到识别变量类型的困难。例如,看起来很容易查看内存中对象的内容,但是如何知道对象中的第一个变量是double类型的呢?我期待着对这个问题的回答。 - Kirby
1
所有的变量都是双精度浮点数吗?它们的数量固定吗?那么可以使用 std::array<double, 18> 或者一个普通的 double[18] - BatchyX
人们没有提到的一件事是,不像一些脚本语言,C++中没有一种方法可以枚举随机类型的成员变量。需要对结构有深入的了解才能操作这些值。 - cppguy
5个回答

3

我假设您的成员变量不会全部具有相同的类型。否则,您可以将它们抛入容器中。如果您使用的是C++11,则可以使用tuple解决此问题。通过一些模板元编程技巧,您可以模拟对元组中所有元素的循环操作。函数std::tie会建立一个包含指向所有成员变量引用的元组,您可以像这样“迭代”它:

struct DoCorrection
{
    template<typename T>
    void operator()(T& t) const { /* code goes here */ }
};

for_each(std::tie(x, y, z), DoCorrection());
// see linked SO answer for the detailed code to make this special for_each work.

然后,您可以为每个成员变量类型专门编写operator()函数。这将使您可以自动执行适当的数学计算,而无需手动跟踪类型。

2

取自glm(详见vec3.incl)

template <typename T>
GLM_FUNC_QUALIFIER typename tvec3<T>::value_type & 
tvec3<T>::operator[]
(
    size_type i
)
{
    assert(i < this->length());
    return (&x)[i];
}

这将翻译为您的示例:

class VariableClass{
public :
  //each object of this class represents an event for this particlular data
  double x;
  double y;
  double z;

  double & operator[](int i) {
    assert(i < 3);
    return (&x)[i];
  }
}

VariableClass foo();
foo.x = 2.0;
std::cout << foo[0] << std::endl; // => 2.0

虽然对于向量数学,我会推荐使用glm。

4
这很不安全。你不能保证编译器不会填充数据以使其更有效地访问。你至少应该添加一个 #pragma pack(1) 或类似的内容来解决这个问题。 - Qortex
这就是为什么我推荐使用这个库。这个库经过测试。我只是想展示一下这个库作为标准容器的替代选择,以防他也需要通过 foo.x 访问。是的,你说得对,这是不安全的。 - scones

1

是的,只需将所有变量放入容器中,例如 std::vector


2
或者使用 std::tuple(如果它们具有不同的类型)。 - BatchyX
是的,但看起来这里并不是这种情况,对吧? - piokuc
1
看,我一直在思考如何使用向量来解决这个问题...但是我应该如何实现它呢?也许我需要以不同于上述方法的方式循环遍历我的事件和变量。但这比简单地创建一个向量更棘手。或者说,我可能正在过度复杂化这个问题。 - Wakka Wakka Wakka
其实,我已经想出如何将其向量化了。毕竟并不难。感谢您的建议! - Wakka Wakka Wakka

1

0

通常情况下,您无法迭代成员而不依赖于实现定义的内容,如填充或具有不同访问限定符的部分的重新排序(实际上没有编译器执行后者-尽管允许)。

但是,您可以使用记录类型的概括:一个std::tuple。 迭代元组不是直截了当的,但您会发现有很多代码可以做到这一点。 最糟糕的是丢失命名变量,但您可以使用成员模仿它。

如果您使用Boost,则可以使用Boost.Fusion的帮助宏BOOST_FUSION_ADAPT_STRUCT将结构体转换为Fusion序列,然后您可以将其与Fusion算法一起使用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接