0

How in C++03 get in compile time number of members of chosen struct? I was experimenting with BOOST_FUSION_ADAPT_STRUCT but I did't get any working example.

I want to generate switch statement in compile time, where there will be one case per each member. So lets say we have struct with 3 members then I want to generate this switch:

switch(val)
{
   case 0:
       break;
   case 1:
       break;
   case 2:
       break;
}

In each statement I will call template function with some parameters. One of this parameters is a member of structure.

How I can do something like this?

Yoh Deadfall
  • 2,711
  • 7
  • 28
  • 32
Adrian
  • 71
  • 1
  • 12
  • Use a container, such as `std::vector`, `std::map` or some such? Or explain further why those won't do what you wish to achieve... – Mats Petersson Jul 29 '15 at 22:59
  • 1
    Containers are pretty different than counting members of struct, if op has already looked at an advanced library like fusion I think we should give him the benefit of the doubt that he really needs it. – Nir Friedman Jul 29 '15 at 23:06
  • @NirFriedman: Really? It would be about the first time I've seen a request for "introspection" or "reflection" where the actual answer is "yes, here is a way for the compiler to tell you the information you need". – Mats Petersson Jul 29 '15 at 23:09
  • @Adrian: You probably need to explain what it is you want to do IN your cases inside the switch too... – Mats Petersson Jul 29 '15 at 23:09
  • 1
    @MatsPetersson I understand what you're saying, but I really do think that when in doubt, you need to give people the benefit of the doubt. I've said "You really want X" in many answers in comments, but past a certain point, people start to feel like it's impossible to ask a question on SO without spending a ton of time justifying their need. – Nir Friedman Jul 29 '15 at 23:19

2 Answers2

1

If you define the struct itself with BOOST_FUSION_DEFINE_STRUCT, boost will generate your struct in such a way that you can easily do this:

#include <boost/fusion/include/define_struct.hpp>
#include <boost/fusion/include/size.hpp>
#include <boost/fusion/include/for_each.hpp>


#include <iostream>
#include <string>

// demo::employee is a Fusion sequence
BOOST_FUSION_DEFINE_STRUCT(
    (),
    employee,
    (std::string, name)
    (int, age))

int main() {
  employee e{"hey", 5};
  int x = boost::fusion::size(e);
  std::cerr << x << std::endl;

  auto print = [] (auto v) { std::cerr << v << std::endl; };

  boost::fusion::for_each(e, print);
  return 0;
}

I modified the code above to also iterate over the members of the struct and apply a generic function. It seems like this functionally does the same thing as your hypothetical case statement would.

The reason you cannot pass the "2" this code generates to boost preprocessor macros is because the preprocessor runs first, before the code, you can't feed a number generate at compile time or at runtime into the preprocessor.

This program prints:

2
hey
5

See:

  1. BOOST_FUSION_DEFINE_STRUCT in boost::fusion documentation

  2. size in boost::fusion documentation

  3. Iterating over Boost fusion::vector

Yoh Deadfall
  • 2,711
  • 7
  • 28
  • 32
Nir Friedman
  • 17,108
  • 2
  • 44
  • 72
  • How you will generate case statements? I had problem with passing that "2" into BOOST_PP_REPEAT and on top of that generate case statements. May you extend your example and show how it will generate case statements in switch? – Adrian Jul 29 '15 at 23:33
  • I realized my for_each isn't exactly equivalent to your case, I got a bit off the point. However, you can construct an appropriate lambda so that it will increment some captured variable, and only execute code when the increment matches a passed in runtime variable. – Nir Friedman Jul 30 '15 at 00:16
  • Thank you for your effort but I managed do what I needed - added sample code. – Adrian Jul 30 '15 at 01:24
1

After long searching, reading and finding this article. I managed to iterate over members from 0 to count - 1 (from that creating switch statement is easy).

#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/fusion/include/define_struct.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/seq.hpp>
#include <boost/preprocessor/seq/cat.hpp>

struct MyStruct
{
    int x;
    int y;
};

#define GO(r, data, elem) elem
#define SEQ1 ((int,x))((int,y))

BOOST_FUSION_ADAPT_STRUCT( 
    MyStruct,
    BOOST_PP_SEQ_FOR_EACH(GO, ,SEQ1)      
    )

#define PRINT(unused, number, data) \
    std::cout << number << std::endl;

int main()
{
    BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(SEQ1), PRINT, "data")
}

Now BOOST_PP_REPEAT may create case statements.

Yoh Deadfall
  • 2,711
  • 7
  • 28
  • 32
Adrian
  • 71
  • 1
  • 12