0

I have many bool variables in struct Flags as:

struct Flags
{
    bool isATrue;
    bool isBTrue;
    bool isCTrue;
    ...
}

then in the other function I have calculate the bool result value of these Variables, now I have to put the variables which was true in the new Vector.e.g. if isBtrue == true. I have to put isBtruein the Vector TrueFlags. but C++ didn't support for() loop to iterate the struct. any one have some good idea?how to iterate struct in C++?

NutCracker
  • 11,485
  • 4
  • 44
  • 68
Ron
  • 46
  • 4
  • 1
    Hard to say what you need without more context but perhaps a `std::map` or some other container is what you want, rather than a struct? – Adomas Baliuka Jan 13 '21 at 08:32
  • 2
    sorry to say but you have two choices: 1) doing manually, 2) change the data structure – Massimo Costa Jan 13 '21 at 08:33
  • Take a look at the `std::bitset`. This might be what you are looking for – NutCracker Jan 13 '21 at 08:36
  • [`std::bitset`](https://en.cppreference.com/w/cpp/utility/bitset) does not provide `begin` and `end` – `std::array` might be an alternative, allowing range based for loop (losing advantage of compressed bools, gaining slightly faster access). In any case you might want to have an enum identifying the indices such that you can do e. g. `allFlags[CFlag]` to access what was formerly `isCTrue`. – Aconcagua Jan 13 '21 at 08:50
  • Are you *required* to retain the struct as is for some reasons? Is changing the data structure an option at all? – Aconcagua Jan 13 '21 at 09:13
  • Side note: *'if `isBtrue == true` I have to put `isBtrue` in the Vector `TrueFlags`'* – what kind of vector is this at all? Pointers? `std::ref`? If just `bool`, then forget about the vector, you lose any association between value and variable anyway. Then rather just count all occurrences in a variable of e.g. `size_t`. – Aconcagua Jan 13 '21 at 09:17

5 Answers5

2

You can use std::bitset and have:

// 3 stands for 3 flags you have in your struct
std::bitset<3> flags;

flags.set(0); // set bit at position 0 to true
flags.set(2); // set bit at position 2 to true

and then you can loop through it:

for (std::size_t i{ 0 }; i < flags.size(); ++i) {
    // access with flags[i]
}

You can also create an enum for direct flag access like:

enum Flags {
    IsATrue = 0,
    IsBTrue,
    IsCTrue
};

and then use it like: flags[IsATrue].

NutCracker
  • 11,485
  • 4
  • 44
  • 68
  • 1
    Recommending yet to provide an enum for direct flag access (`flags[IsATrue]`), which likely should be retained (why members otherwise?). – Aconcagua Jan 13 '21 at 08:54
0

If the number of values is fixed and known in advance, you can use array<bool>, otherwise use vector<bool>. Likewise for the is_true variable. Then you can easily loop over it.

U. W.
  • 414
  • 2
  • 10
0

One way is to use bitset as stated in other answer. But if structure Flags is something you have to use (from whatever reasons, for ex. maybe existing API, etc.), you can use operations wrapper and pointer to member to achieve "loop-ability". Something like (see Live):

struct Flags
{
    bool isATrue;
    bool isBTrue;
    bool isCTrue;
};

struct FlagsOp
{
    FlagsOp(Flags& f)
        : f{ f }
        , v({ &Flags::isATrue, &Flags::isBTrue, &Flags::isCTrue })
    {}
    size_t size() const { return v.size();}
    bool& operator[](size_t n) { return f.*(v[n]); }
private:
    Flags& f;
    vector<bool Flags::*> v;
};

int main()
{
    Flags f{};
    FlagsOp fop(f);

   fop[0] = true; // isATrue
   fop[1] = true; // isBTrue
   fop[2] = true; // isCTrue

    for (size_t i = 0; i < fop.size(); ++i)
        cout << fop[i] << '\n';
}
StPiere
  • 4,113
  • 15
  • 24
  • Instead of get/set I'd rather provide index operators. More C++ idiomatic... We might we working with `std::ref` in the data structure and the operator allowing modifications might return the raw reference then. – Aconcagua Jan 13 '21 at 09:10
  • Fore completeness: `bool operator[](size_t) const` overload... – Aconcagua Jan 13 '21 at 09:34
0

If you do not want to change your struct Flags there is one other way. But first please read this And notice that this is not a portable solution. You can take advantage of unions by defining a union like this:

union Flagsunion{
    bool flag[sizeof(Flags)/ sizeof(bool)];
    Flags flags;
};

Assuming that the name of your std::vector<bool> is myvector and name of your Flags is myflags Then in your code:

    std::vector<bool> myvector;
    Flags myflags{ true, false, true};
    
    Flags2 my2ndflags;
    my2ndflags.flags = myflags;
    for(int i = 0; i < 3; ++ i){
        myvector.push_back(my2ndflags.flag[i]);
    }
newbie
  • 415
  • 3
  • 11
  • Unfortunately type punning via unions is undefined behaviour in C++ (and there is no exception if only pure PODs are involved). – Aconcagua Jan 13 '21 at 09:43
  • @Aconcagua thank you for the comment. Unfortunately I didn't completely understand it. could you please refer me to a source where I can read more about it? thanks in advance. – newbie Jan 13 '21 at 09:46
  • [Undefined behaviour at cppreference](https://en.cppreference.com/w/cpp/language/ub). – Aconcagua Jan 13 '21 at 09:49
  • Might be of interest, too: https://stackoverflow.com/questions/25664848/unions-and-type-punning. Actually, some compilers *do* allow type punning as language *extension*. But then you rely on such compilers, thus at least you write non-portable code. – Aconcagua Jan 13 '21 at 09:52
  • dear @Aconcagua I have already mentioned that. Please read the last part of my answer. Any way if you think This is bad answer, tell me to delete it. – newbie Jan 13 '21 at 09:58
  • @Aconcagua I edited my answer according to what you mentioned. And thank you so much for correcting me! – newbie Jan 13 '21 at 10:09
  • Last paragraph actually is incorrect as well. Compiler is allowed to re-order member variables only in limited ways; within *same visibility group* – which is the case here – members are required to appear in memory in the same order as they are defined. Thus flags[0] is guaranteed to be at the same location as first member variable `isATrue`. That's not where unportability arises from. In any case, if you have a non-portable solution, it is a good idea to mention it right at the start. At the very end, people might have stopped reading already. – Aconcagua Jan 13 '21 at 10:45
0

how to iterate struct in C++?

Same way as you would iterate anything that doesn't have a pre-existing standard iterator: By writing a custom iterator.

Writing custom iterators isn't simple, and writing this custom iterator is particularly complex due to lack of introspective language features, , . An incomplete, simplified example:

struct Flags
{
    bool isATrue;
    bool isBTrue;
    bool isCTrue;

    struct iterator {
        Flags* flags;
        int index;
        
        bool& operator*() {
            switch(index) {
                case 0: return flags->isATrue;
                case 1: return flags->isBTrue;
                case 2: return flags->isCTrue;
                default: throw std::out_of_range("You wrote a bug!");
            }
        }
        iterator& operator++() {
            index++;
            return *this;
        }
        iterator operator++(int) {
            iterator next = *this;
            index++;
            return next;
        }
        friend auto operator<=>(const iterator&, const iterator&) = default;
    };
    
    iterator begin() {
        return {this, 0};
    }
    iterator end() {
        return {this, 3};
    }
};

Note that although it is possible to iterate members of a class in C++, this is not necessarily efficient. It may be advisable to use an array instead of a class if you need efficient iteration.

eerorika
  • 232,697
  • 12
  • 197
  • 326