我有两个类,例如
struct point{
dint data
};
class data{
...
public:
point left;
point right;
..... //more that 50 members of point
point some_other_point;
}example;
在这种情况下,是否可以使用“point
中的每个example
”之类的内容?
因为现在我需要修改许多功能,如果我再添加一个point
到data
。
或许,还有其他任何想法。
答案 0 :(得分:4)
不,你不能枚举一个类型的成员,因为C ++没有 reflection 的概念。
这是数组, vector 或 map 的常见用例。
答案 1 :(得分:2)
这样做:
class data{
public:
enum POINTS {LEFT=0,RIGHT,SOME_OTHER_POINT};
std::array<point,50> points; // or just point points[50];
}example;
并像这样使用它:
example.points[data::LEFT]=point{};
然后,您可以使用标准技术迭代点数组。
答案 2 :(得分:2)
是,有两种方法:
然后迭代逻辑被封装在这些类中的任何一个中,并且所有代码都只使用它们。
使用迭代器类。
优点:
for
和while
循环缺点:
示例:
class DataIterator;
class Data {
public:
friend class DataIterator;
Data(Point a, Point b, Point c): _one(a), _two(b), _three(c) {}
DataIterator begin();
DataIterator end();
private:
Point _one;
Point _two;
Point _three;
}; // class Data
class DataIterator:
public std::iterator<std::forward_iterator_tag, Point>
{
public:
struct BeginTag{};
struct EndTag{};
DataIterator(): _data(0), _member(0) {}
DataIterator(Data& data, BeginTag): _data(&data), _member(0) {}
DataIterator(Data& data, EndTag): _data(&data), _member(N) {}
reference operator*() const {
this->ensure_valid();
MemberPtr const ptr = Pointers[_member];
return _data->*ptr;
}
pointer operator->() const { return std::addressof(*(*this)); }
DataIterator& operator++() { this->ensure_valid(); ++_member; return *this; }
DataIterator operator++(int) { DataIterator tmp(*this); ++*this; return tmp; }
friend bool operator==(DataIterator const& left, DataIterator const& right) {
return left._data == right._data and left._member == right._member;
}
friend bool operator!=(DataIterator const& left, DataIterator const& right) {
return not (left == right);
}
private:
typedef Point Data::*MemberPtr;
static size_t const N = 3;
static MemberPtr const Pointers[N];
void ensure_valid() const { assert(_data and _member < N); }
Data* _data;
size_t _member;
}; // class DataIterator
//
// Implementation
//
DataIterator Data::begin() { return DataIterator(*this, DataIterator::BeginTag{}); }
DataIterator Data::end() { return DataIterator(*this, DataIterator::EndTag{}); }
size_t const DataIterator::N;
DataIterator::MemberPtr const DataIterator::Pointers[DataIterator::N] = {
&Data::_one, &Data::_two, &Data::_three
};
万一你想知道:yes, it really works。
然而,使用访问方法更容易。
优点:
缺点:
示例:
class Data {
public:
Data(Point a, Point b, Point c): _one(a), _two(b), _three(c) {}
template <typename F>
void apply(F&& f) {
f(_one);
f(_two);
f(_three);
}
private:
Point _one;
Point _two;
Point _three;
}; // class Data
当然,it works too。
答案 3 :(得分:1)
您可以将当前字段转换为:
private:
point left;
// ..
public:
point& left() { return points[LEFT]; }
// ..
其中points可能是一个点数组(如在其他答案中),而LEFT是数组的常量索引。这应该允许相对快速和无痛的转换,您只需要添加()
,编译器将输出错误应用修复的位置。
然后,您可以转换代码以迭代您的点值。
答案 4 :(得分:1)
您可以为每个函数编写一个而不修改您的示例:
template<class Func>
void for_each_point(example& e, Func&& f){
f(e.pt1);
f(e.pt2);
f(e.blah);
...
f(e.last_pt);
}
然后将其称为:
for_each_point(exam, [&](point & pt){
std::cout<<pt.data<<"\n";
});
或做任何事情。
如果您愿意,此函数也可以是成员变量。
将tye点存储更改为数组或std::array
amd公开begin
和end
或数组也可以。
最后,您可以编写一个自定义迭代器来处理这些点,但这可能是不明智的。