任何“为每个”提示

时间:2014-01-26 14:43:47

标签: c++

我有两个类,例如

struct point{
dint data
};

class data{
 ...
public:
 point left;
 point right;
 ..... //more that 50 members of point
 point some_other_point;

}example;

在这种情况下,是否可以使用“point中的每个example”之类的内容? 因为现在我需要修改许多功能,如果我再添加一个pointdata。 或许,还有其他任何想法。

5 个答案:

答案 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)

,有两种方法:

  • 迭代器类,用于外部迭代
  • 一种访问方法,用于内部迭代

然后迭代逻辑被封装在这些类中的任何一个中,并且所有代码都只使用它们。


使用迭代器类。

优点:

  • 可以轻松地与现有的STL算法结合使用,以及forwhile循环
  • 可以暂停(并恢复)迭代

缺点:

  • 需要迭代的属性的多态性

示例:

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


然而,使用访问方法更容易。

优点:

  • 可以轻松适应迭代的
  • 属性类型的差异

缺点:

  • 不能与现有的STL算法或现有循环结合使用
  • 很难暂停迭代部分

示例:

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公开beginend或数组也可以。

最后,您可以编写一个自定义迭代器来处理这些点,但这可能是不明智的。