0

I have the following struct:

struct myHandler
{
  bool test1;
  bool test2;
  ...
  bool test400;
};

Which has about 400 test values. So currently I have the following function:

static inline void DoSomething(myHandler& hdler, int test, bool passed)
{
  #define SETTEST(a,b,c) case b: a.test##b=c;

  switch (test)
  {
    SETTEST(hdler, 1, passed)
    SETTEST(hdler, 2, passed)
    ...
    SETTEST(hdler, 400, passed)
  }

  #undef SETTEST
};

I am obviously trying to get rid of repetitive code as there are a lot of tests. So I have tried the following two options: Option1:

static inline void DoSomething(myHandler& hdler, int test, bool passed)
{
  #define SETTEST(a,b,index,c) if(index==b) a.test##b=c;

  for(i = 1; i <= 400; ++i)
  {
    SETTEST(hdler, test, i, passed)
  }

  #undef SETTEST
};

Obviously this does not compile, as when it concatenates using ## it takes "test" literally. Don't know how or if I can get around this.

Option2:

template<typename FUNCTION>
inline void setTest(FUNCTION f) {
  for (int i = 1; i <= 5; ++i) {
    f(i);
  }
};

static inline void DoSomething(myHandler& hdler, int test, bool passed
{
  setTest([&](const int testNum) { 
    if(test == testNum) {
      hdler.test##testNum = passed;
    }
  });
};

Obviously option2 won't compile either, I don't know how to access the member of the struct using some dynamic form. Now, there are some changes to the actual struct that will solve this easily, however modifying the struct is not an option as it gets formed through some other methods, and this is just example code to portray my problem. I just want to know if there is a way to do what I am trying to achieve (without modifying the struct) that I have missed. Really I am leaning towards option 2, however from what I have read there is no way of concatenating dynamically to access a member. Any help is appreciated.

arias_JC
  • 549
  • 3
  • 15

4 Answers4

3

Why not to do this:

struct myHandler {
   bool test[400] = {};
};

PS. And no, the thing you are trying to do is impossible, because you're trying to mix code preprocessing or compile time and execution time. Some may think about recursive templates, but again, you can't do that either for same reason as you can't do that in template.

Best (and worst) effort you can do it to access struct through char*. Any code reviewer would make a wine goblet from your skull for doing that either. Specifically, this is an anti-pattern (usually):

myHandler s {};
unsigned char* p = reinterpret_cast<unsigned char*>(&s);

int index_value = 200;
int n = 0;
// sets index_value-th element to true.
std::generate(p, p+sizeof(s), [&n,=](){ return (++n)==index_value; })
//                    your "array" starts with 1^^^        

It would be a little fancy if bool isn't equal to char.. or if you need a larger type. generate does increment by 1 only. But you can iterate through array by any way possible.

Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42
  • 1
    This is not an answer - it's a question! – Support Ukraine May 16 '17 at 19:18
  • 2
    @4386427 No, it is an answer in the form of a rhetorical question. It is, in fact, _the_ answer. – Lightness Races in Orbit May 16 '17 at 19:19
  • @4386427 it;'s called rhetoric question. By the way, why doesn't always mark a question in English. It also used to " express indignation, mild surprise, or impatience". Here it is a little of both, as I used bare infinitive clause after it. (Note: English is not my native language) – Swift - Friday Pie May 16 '17 at 19:21
  • @BoundaryImposition - Well, I disagree. This does **not** answer the question. It suggest an alternative approach which may not be relevant at all. The basis of the question is that the struct is as it is. We don't know if OP can change the struct. Anyway, OP doesn't seem to care about the question as OP doesn't answer the questions in the comments. – Support Ukraine May 16 '17 at 19:28
  • @4386427: You're permitted to disagree. :) Even though you're wrong! – Lightness Races in Orbit May 16 '17 at 19:29
  • @BoundaryImposition So be it :) Even though you're wrong! – Support Ukraine May 16 '17 at 19:43
  • Just to underline why this isn't an answer. OP write: ` I just want to know if there is a way to do what I am trying to achieve (**without modifying the struct**)`. – Support Ukraine May 16 '17 at 19:50
  • @4386427 there is no way to do that, really, unless using some kind of code generator – Swift - Friday Pie May 16 '17 at 20:25
  • @4386427 Ah, I had my moment of being dumb, lol. Happens. Paraphrasing Sherlock Holmes, if all other options are impossible, the only one left is the right answer, irregardless of its relevance. There is such thing as BadCode. Building more BadCode to support BadCode, instead of refactoring of BadCode, is a BadCode in power two XD – Swift - Friday Pie May 16 '17 at 20:32
  • OP does care about this question. Op also believes this does not answer the question. – arias_JC May 17 '17 at 11:02
  • 1
    @arias_JC OP might like to know that this one had tried to solve this xy problem in different situation(with function calls) 15 years ago, mostly out of ignorance. I can vouch that such code is not needed, doesnt cost the time spent to solve, and generally regarded as bad way of designing code. Best thing you can do is to put my structure and your structure into a union and access the fields by index. And that is formally an UB. If OP woul be kind to explaind y problem solved by this code, we might come with solution to x, that is realistic. – Swift - Friday Pie May 17 '17 at 16:11
3

Boost PP shines again.

#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>

#define SET_TEST(z, n, data) \
    case n: hdler.BOOST_PP_CAT(test, n) = passed; break;
//             Note : was the break missing here? ^^^^^^

switch (test)
{
    BOOST_PP_REPEAT_FROM_TO(1, 400, SET_TEST, ~)
}

#undef SET_TEST

Oh -- you'll need a custom build of Boost.PP so it goes up to 400 instead of the default 256 :)

No seriously... please use an array if you can.

Quentin
  • 62,093
  • 7
  • 131
  • 191
0

There is no way you can write a few lines of code to access the individual members of your struct.

Macros and templates is to resolved at compile time so you can't write a macro-like function that access members at runtime.

So, if you are really stuck with a struct like that, you have to write a wrapper that can hide the rather ugly nature of the struct. It will still take a lot of lines to write the wrapper but once that is done, the other parts of your code will be more simple.

It could look like:

#include <iostream>
#include <array>
using namespace std;

struct myHandler
{
  bool test1;
  bool test2;
  // ..
  bool test400;
};

struct myHandlerWrapper
{
    myHandlerWrapper(myHandler& mh)
    {
        h[0] = &mh.test1;
        h[1] = &mh.test2;
            // .. 
        h[399] = &mh.test400;
    }

    bool& operator[](size_t i)  // This gives the easy access to members using simple indexing
    {
        return *h[i];
    }

    private:
    array<bool*, 400> h;
};

int main() {
    myHandler mh;
    myHandlerWrapper handler(mh);

    handler[0] = false;  // Access members using simple indexing via the wrapper
    handler[1] = true;

    cout << (handler[0] ? "true" : "false") << endl;
    cout << (handler[1] ? "true" : "false") << endl;

    return 0;
}
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
0

I don't think there's an easy solution to your problem here, but you could try the top answer here.

It discusses if it's possible to iterate through a struct's members (which isn't possible in C++), and offers an alternative using Boost, if that's an option for you.

Community
  • 1
  • 1
forsamori
  • 21
  • 7
  • 1
    boost is just a library for C++.. there ARE ways to iterate through storage, actually, if one would ditch the structure altogether, they may use std::tuple.. but tuple in general needed only with different types of "fields", with same type we would use array\vector\list> Pretty much it's difference between definition of structure(aka record) and array as long as programming languages existed. – Swift - Friday Pie May 16 '17 at 20:39
  • Yeah, I know it's a library, just referring to it in a general way without taking too much from someone else's answer. I'd be super interested in seeing a way to iterate through a struct's members though. – forsamori May 16 '17 at 21:19
  • I had such problem in project at work.. for one reason: we had to automate generation of code that was doing hton\ntoh with various fields. In result we had to use a parser program which does it for us. The code it generated used pointer to shuffle through structure, but strides were calculated by parser instead of by hand. Parser simply was taking header file with structure declarations and was generating file with functions (actually methods for a serialization classes) for each structure found – Swift - Friday Pie May 16 '17 at 21:22
  • 1
    For this question, could OP have made the struct contiguous in memory, allowing them to iterate that way? Probably not the safest way to do it though. – forsamori May 16 '17 at 21:26
  • well, it same size fields.. so it is continuous. His struct got same standard layout as an array. Maybe on SPARC it will not be, does Solaris compiler treat bool as an int? Actually there are compiler specific ways to force continuous if platform thinks otherwise. `#pragma pack` in case of VC or GCC. The padding is actually predictable, our parser was taking it in account, carefully designed struct won't have gaps either. – Swift - Friday Pie May 16 '17 at 21:30