你有一个简单的结构,比如说:
typedef struct rect
{
int x;
int y;
int width;
int height;
}
rect;
并且您希望将每个元素乘以一个因子。有没有更简洁的方法来执行此操作,除了将每个成员乘以值?
答案 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>
上定义的向量运算。
我不一定会推荐这种方法。我只是建议可以做到。