有没有办法在c ++中将函数应用于结构的每个成员?

时间:2010-09-30 16:24:02

标签: c++

你有一个简单的结构,比如说:

typedef struct rect
{
    int x;
    int y;
    int width;
    int height;
}
rect;

并且您希望将每个元素乘以一个因子。有没有更简洁的方法来执行此操作,除了将每个成员乘以值?

13 个答案:

答案 0 :(得分:10)

不是真的。以编程方式获取结构元素的列表需要反射,C ++不支持。

你的两个选择是给结构一个方法,这个方法以冗长的方式执行,然后在所有其他地方使用该方法,或者手动模仿反射,例如通过给结构另一个元素是一个数组指向其所有其他元素的指针(在struct的构造函数中构建),然后循环遍历它以执行缩放功能。

答案 1 :(得分:10)

没有;没有办法迭代结构的成员。

但在这种特殊情况下,您可以使用数组来实现目标:

struct rect
{
    // actually store the data in an array, not as distinct elements
    int values_[4];

    // use accessor/mutator functions to modify the values; it is often best to
    // provide const-qualified overloads as well.
    int& x()      { return values_[0]; }
    int& y()      { return values_[1]; }
    int& width()  { return values_[2]; }
    int& height() { return values_[3]; }

    void multiply_all_by_two()
    {
        for (int i = 0; i < sizeof(values_) / sizeof(values_[0]); ++i)
            values_[i] *= 2;
    }
};

(请注意,这个例子没有多大意义(为什么你会将x,y,高度和宽度乘以2?)但它会演示一种不同的方法来解决这类问题)

答案 2 :(得分:10)

Boost.Fusion提供BOOST_FUSION_ADAPT_STRUCT宏,它可以将任何结构转换为Fusion序列,然后Fusion可以迭代(如Quick Start中所示)。

另一种选择是使用第三方C ++反射库(如Reflex)来迭代结构的成员。

然而,所有这些对你的目的来说可能是过度的;手动列出每个类的成员可能不那么优雅,但它更简单,编码的简单性很重要。

答案 3 :(得分:5)

如果所有值都适合128位向量,那么您可以使用SIMD指令将它们全部相乘。例如,英特尔的集成性能基元(IPP)具有primitives,用于向量上的加法,减法,乘法等。

除非您正在进行大量的计算密集型操作,否则它可能过度杀伤。

答案 4 :(得分:2)

如果所有都是相同的类型,请在结构中使用一个与匿名结构相结合的联合:

struct MyStruct {
  union {
    int data[4];
    struct {
      int x,y,z,w;
    }
  };
};

然后:

MyStruct my_struct;
cout << my_struct.x << my_struct.y << my_struct.z << my_struct.w;
for (size_t i = 0; i < 4; ++i)
  some_function(my_struct.data[i]); // access the data via "data" member
cout << my_struct.x << my_struct.y << my_struct.z << my_struct.w; // voila!, stryct data has changed!

如果您使用不同类型,请查看boost::fusion

答案 5 :(得分:2)

就像每个人都说的那样,你不能直接做到,但没有什么可以阻止你超载*运算符:

struct rect 
{ 
   int x; 
   int y; 
   int width; 
   int height; 
}

rect operator*(const rect& r, int f)
{
  rect ret=r;
  ret.x*=f;
  ret.y*=f;
  ret.width*=f;
  ret.height*=f;
  return ret;
}

然后你可以这样做

rect r;
//assign fields here
r=r*5;

答案 6 :(得分:2)

假设您使用的是C ++编译器(而不是C),请将其设为类并创建成员函数来执行此操作。我对一个简单问题提出的所有尴尬解决方案感到惊讶。反光解决方案给你带来了什么?您是否不断在此类中添加新成员,因此您希望将来自己保存修改成员函数的步骤?如果这确实是一个潜在的节省时间的话,它会让一个阶级做得太多。

不可避免地会有重复的功能作用于结构的成员,那么为什么不从一开始就使它成为一个类?

答案 7 :(得分:1)

好吧,不是直接的。但是你可以通过使用指向成员类型的指针的附加临时“索引”数组来实现这一点。

例如

rect a_rect[100];
int factor;
...
// We need to multiply all members of all elements of `a_rect` array by `factor`

// Prepare index array
int rect::*rect_members[4] = { &rect::x, &rect::y, &rect::width, &rect::height };

// And multiply
for (i = 0; i < 100; ++i)
  for (j = 0; j < 4; ++j)
    a_rect[i].*rect_members[j] *= factor;

当然,如果您需要经常这样做,可以使用在程序启动时初始化的永久索引数组rect_members

请注意,此方法不会像其他一些方法那样使用任何黑客攻击。指向成员类型的指针很少使用,但实际上这是它们引入的内容之一。

同样,如果你需要经常这样做,那么正确的做法是使指针数组成为结构的static const成员

struct rect
{
  int x;
  int y;
  int width;
  int height;

  static int rect::* const members[4];
};

int rect::* const rect::members[4] = { &rect::x, &rect::y, &rect::width, &rect::height };

当您需要迭代这些成员时,您只需将结构元素作为s.*rect::members[i]进行访问。

答案 8 :(得分:0)

如果您的所有元素属于同一类型:

for (int i = 0; i < sizeof(rect) / sizeof(rect.x) ; ++i) {
    do_something(reinterpret_cast<int *>(adress_of_your_struct) + i);
}

do_something期待指向int

的指针

答案 9 :(得分:0)

可怕的黑客

int *arr = (int*)&my_rect;
for (int i = 0; i < sizeof(rect)/sizeof(int); i++)
{
     arr[i] *= factor;
}

答案 10 :(得分:0)

通过新课程的解决方案:

  • 创建一个包含template<class T> class Array通用数组的类(请参阅how),
  • 使用您的属性填充数组,将一个属性作为数组的元素。
  • 确保所有类型都可以乘以数值(如果需要,可以为*运算符重载类型/为该对象创建特定方法)
  • 创建一个方法multiply,在数组上执行循环,并将每个元素乘以给定值。

答案 11 :(得分:0)

如果你可以重新安排你的结构取代联盟,你可以做类似于微软用DirectX做的事情。

union Rect
{
    struct
    {
        int x;
        int y;
        int width;
        int height;
    };

    int members[4];
};

void multiply(Rect& rect, int factor)
{
    for(int i = 0; i < 4; i++)
    {
        rect.members[i] *= factor;
    }
}

答案 12 :(得分:0)

从标准类继承有一些问题;但是如果你愿意接受这些问题,你可以做一些类似于其他人建议的事情,但是使用std::valarray代替。它看起来像是:

#include <valarray>

class rect : public std::valarray<int>
{
  public:
    rect() : std::valarray(4, 0) {}

    int& x() { return (*this)[0]; }
    int& y() { return (*this)[1]; }
    int& width() { return (*this)[2]; }
    int& height() { return (*this)[3]; }
};

通过这种方式,您可以继承std::valarray<int>上定义的向量运算。

我不一定会推荐这种方法。我只是建议可以做到。