58

I have a structure

typedef struct A
{
    int a;
    int b;
    char * c;
}aA;

I want to iterate over each an every member of the structure and print its value. Something like:

void print_struct_value(struct *A)
{
    for each member of struct A
    cout << "struct name . member name" << "value";
}

How can this be done in C++ ??

jh314
  • 27,144
  • 16
  • 62
  • 82
msd_2
  • 1,117
  • 3
  • 16
  • 22
  • Start with something simpler: how would you print the `a` field of that `A`? – Beta Jul 15 '13 at 17:29
  • Your sample looks like antiquated [tag:c]. In my answer I have, as a side-note, ironed out those spots. – sehe Jul 15 '13 at 17:39
  • I can't see a use for this unless the fields of your data structure are undetermined until runtime. And in that case typedef struct is not the right way to go about whatever you're trying to accomplish. – Jamin King Jul 15 '13 at 17:41
  • 5
    In C++14 it become possible, see this lecture: CppCon 2016: C++14 Reflections Without Macros, Markup nor External Tooling.. https://www.youtube.com/watch?v=abdeAew3gmQ – Nir Jun 07 '17 at 07:02
  • 1
    Check out: a related [question](https://stackoverflow.com/questions/67033605/applying-std-algorithms-over-structs), my sample [solution](https://github.com/user1095108/generic/blob/master/structiterator.cpp) and the amazing [Boost.PFR](https://apolukhin.github.io/magic_get/). – user1095108 Apr 19 '21 at 16:00
  • this post deserves an answer based on reflection TS – madhur4127 Jan 07 '23 at 05:16

8 Answers8

39

Perhaps you can string something together using Boost Fusion/Phoenix:

See it live on Coliru!

#include <boost/fusion/adapted/struct.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/phoenix/phoenix.hpp>
using boost::phoenix::arg_names::arg1;

#include <string>
#include <iostream>

struct A
{
    int a;
    int b;
    std::string c;
};

BOOST_FUSION_ADAPT_STRUCT(A, (int,a)(int,b)(std::string,c));

int main()
{
    const A obj = { 1, 42, "The Answer To LtUaE" };

    boost::fusion::for_each(obj, std::cout << arg1 << "\n");
}

Update: Recent versions of boost can use C++11 type deduction:

BOOST_FUSION_ADAPT_STRUCT(A,a,b,c);

Output:

1
42
The Answer To LtUaE
sehe
  • 374,641
  • 47
  • 450
  • 633
24

You can't iterate over an object's data members. You can use std::ostream's stream insertion operator to print individually however:

struct A
{
    int a;
    int b;
    std::string c;

    friend std::ostream& operator <<(std::ostream& os, A const& a)
    {
        return os << a.a << '\n'
                  << a.b << '\n'
                  << a.c << '\n';
    }
};

And inside main:

int main()
{
    A a = {5, 10, "apple sauce"};

    std::cout << a;
}

Output:

5
10
apple sauce

Here is a demo.

David G
  • 94,763
  • 41
  • 167
  • 253
  • 1
    This made my debugging easier and helping me catch a couple of mistakes right away. – Lorien Brune Sep 30 '17 at 05:30
  • Note that adding the output stream function to the struct requires the struct to be declared a certain way, so if anybody is getting errors trying to implement this, the location of the struct name (in this example, `A`) is a good first place to look. `struct A { ... };` and `typedef struct A { ... } A;` are both okay, but `typedef struct { ... } A;` will get you in trouble. – Lorien Brune Sep 30 '17 at 05:32
  • This doesn't answer how to print the member *names*, which was part of the question. – Ð.. Jun 21 '18 at 14:08
  • @Wand `return os << "a: " << a.a << '\n' << ...` – Tᴏᴍᴇʀ Wᴏʟʙᴇʀɢ Jul 16 '18 at 13:11
  • @TᴏᴍᴇʀWᴏʟʙᴇʀɢ Yeah that would do it. I was hoping there would be something more "reflective" that didn't require hardcoding anything, but I've been working with "reflective" metaprogramming libraries like Boost.Hana for the past few months that do provide iteration over member names, and it turns out that something like the macro BOOST_HANA_DEFINE_STRUCT (see the [Structure Concept in Hana](https://www.boost.org/doc/libs/1_61_0/libs/hana/doc/html/group__group-Struct.html)), just ends up using the preprocessor to generate these hardcoded functions from its arguments anyways... – Ð.. Jul 16 '18 at 14:03
  • @TᴏᴍᴇʀWᴏʟʙᴇʀɢ Something like [sehe's answer](https://stackoverflow.com/a/17660354/8245487) on this very same question is similar to the "reflection" I achieved with Boost.Hana, but with Hana's BOOST_HANA_DEFINE_STRUCT macro instead of BOOST_FUSION_ADAPT_STRUCT. I imagine they are similar in implementation too... – Ð.. Jul 16 '18 at 14:12
21

There are a couple of ways to do this, but you need to use some macros to either define or adapt the struct.

You can use the REFLECTABLE macro given in this answer to define the struct like this:

struct A
{
    REFLECTABLE
    (
        (int) a,
        (int) b,
        (const char *) c
    )
};

And then you can iterate over the fields and print each value like this:

struct print_visitor
{
    template<class FieldData>
    void operator()(FieldData f)
    {
        std::cout << f.name() << "=" << f.get() << std::endl;
    }
};

template<class T>
void print_fields(T & x)
{
    visit_each(x, print_visitor());
}

A x;
print_fields(x);

Another way is to adapt the struct as a fusion sequence (see the documentation). Here's an example:

struct A
{
    int a;
    int b;
    const char * c;
};

BOOST_FUSION_ADAPT_STRUCT
(
    A,
    (int, a)
    (int, b)
    (const char *, c)
)

Then you can print the fields as well using this:

struct print_visitor
{
    template<class Index, class C>
    void operator()(Index, C & c)
    {

        std::cout << boost::fusion::extension::struct_member_name<C, Index::value>::call() 
                  << "=" 
                  << boost:::fusion::at<Index>(c) 
                  << std::endl;
    }
};


template<class C>
void print_fields(C & c)
{
    typedef boost::mpl::range_c<int,0, boost::fusion::result_of::size<C>::type::value> range;
    boost::mpl::for_each<range>(boost::bind<void>(print_visitor(), _1, boost::ref(c)));
}
Community
  • 1
  • 1
Paul Fultz II
  • 17,682
  • 13
  • 62
  • 59
17

C++ does not support reflection out of the box, so what you are asking for is impossible within the core language.

Various libraries try to provide such functionality, typically by making you register your fields through some methods or macros, which will behind the scene save them into a collection of some sort, on which you can iterate.

cmh
  • 10,612
  • 5
  • 30
  • 40
small_duck
  • 3,038
  • 20
  • 28
8

can I iterate over the members of a struct in standard c++?

No, standard c++ doesn't provide a method for accomplishing what you are asking for, you "iterate" elements of a container - you cannot iterate over members of a certain type.

"reflection" (as this type of feature is most often referred to isn't part of C++).


in c++11 you could use a std::tuple<int,int,char*> instead of your struct A, it will store the same kind of elements and is far easier to iterate over (using some template magic).

the elements won't have names ranging from 'a' to 'c' but if you'd like to print it that way this of course can be accomplished by some extra lines of code.

To access a specific element you'll use std::get<N> (your_tuple) where N is a integral ranging from 0 to std::tuple_size<std::tuple<int,int,char*>>::value - 1 (ie. 2).


Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
3

As suggested by @Paul I use BOOST_FUSION_ADAPT_STRUCT with a self written for_each_member function :

/**
 * \brief Allows iteration on member name and values of a Fusion adapted struct.
 * 
 *  
 * BOOST_FUSION_ADAPT_STRUCT(ns::point,
 *      (int, x)
 *      (int, y)
 *      (int, z));
 *
 * template<class T>
 * print_name_and_value(const char* name, T& value) const {
 *    std::cout << name << "=" << value << std::endl;
 * } 
 *
 * 
 * int main(void) {
 *  
 *  ns::point mypoint;
 *
 *  
 *      boost::fusion::for_each_member(mypoint, &print_name_and_value);
 *
 *
 * }
 *
 */
#ifndef BOOST_FUSION_FOR_EACH_MEMBER_HPP
#define BOOST_FUSION_FOR_EACH_MEMBER_HPP

#include <functional>

#include <boost/fusion/include/adapt_struct.hpp>

#include <boost/fusion/sequence/intrinsic/begin.hpp>
#include <boost/fusion/sequence/intrinsic/end.hpp>
#include <boost/fusion/sequence/intrinsic/front.hpp>
#include <boost/fusion/iterator/equal_to.hpp>
#include <boost/fusion/iterator/next.hpp>
#include <boost/fusion/iterator/deref.hpp>
#include <boost/fusion/iterator/distance.hpp>
#include <boost/fusion/support/category_of.hpp>
#include <boost/mpl/bool.hpp>

namespace boost { namespace fusion {

namespace detail {

  template <typename First, typename Last, typename F>
  inline void
  for_each_member_linear(First const& first,
      Last const& last,
      F const& f,
      boost::mpl::true_) {}

  template <typename First, typename Last, typename F>
  inline void
  for_each_member_linear(First const& first,
      Last const& last,
      F const& f,
      boost::mpl::false_) {

      f(
                extension::struct_member_name<
                    typename First::seq_type, First::index::value
                >::call(),
                *first
            );

      for_each_member_linear(
          next(first),
          last,
          f,
          result_of::equal_to< typename result_of::next<First>::type, Last>()
      );
  }

  template <typename Sequence, typename F>
  inline void
  for_each_member(Sequence& seq, F const& f) {

    detail::for_each_member_linear(
      fusion::begin(seq),
      fusion::end(seq),
      f,
      result_of::equal_to<
        typename result_of::begin<Sequence>::type,
        typename result_of::end<Sequence>::type>()
    );
  }

}

  template <typename Sequence, typename F>
  inline void
  for_each_member(Sequence& seq, F f) {
    detail::for_each_member(seq, f);
  }

}}

#endif 
daminetreg
  • 9,724
  • 1
  • 23
  • 15
3

If all fields in the structure are the same, you can do

template <typename S> uint64_t* get_begin(S *s)
{
    return (uint64_t*)s;
}

template <typename S> uint64_t* get_end(S *s)
{
    return (uint64_t*)((uint8_t*)s+sizeof(*s));
}

struct statistics_s {
        uint64_t f1;
        uint64_t f2;
} statistics;

for (uint64_t* p = get_begin(&statistics);p < get_end(&statistics);p++)
    printf("%lu ", *p);
Larytet
  • 648
  • 3
  • 13
3

I wrote a version without Boost or other third-party library, which has been tested using GCC 4.9(c++11), clang 5.0(c++11), VS 2008, VS 2019.

#include <iostream>
#include <string>

#define REFLECTION_WITH_FIELD_NAME 1

#define _PP_EVAL(...) __VA_ARGS__
#define _PP_EAT(...)
#define _PP_EMPTY
#define _PP_STR2(x) #x
#define _PP_STR(x) _PP_STR2(x)

#define _PP_MAP01(f, x) f(x)
#define _PP_MAP02(f, x, ...) f(x) _PP_EVAL(_PP_MAP01(f, __VA_ARGS__))
#define _PP_MAP03(f, x, ...) f(x) _PP_EVAL(_PP_MAP02(f, __VA_ARGS__))
#define _PP_MAP04(f, x, ...) f(x) _PP_EVAL(_PP_MAP03(f, __VA_ARGS__))
#define _PP_MAP05(f, x, ...) f(x) _PP_EVAL(_PP_MAP04(f, __VA_ARGS__))
#define _PP_MAP06(f, x, ...) f(x) _PP_EVAL(_PP_MAP05(f, __VA_ARGS__))
#define _PP_MAP07(f, x, ...) f(x) _PP_EVAL(_PP_MAP06(f, __VA_ARGS__))
#define _PP_MAP08(f, x, ...) f(x) _PP_EVAL(_PP_MAP07(f, __VA_ARGS__))
#define _PP_MAP09(f, x, ...) f(x) _PP_EVAL(_PP_MAP08(f, __VA_ARGS__))
#define _PP_MAP10(f, x, ...) f(x) _PP_EVAL(_PP_MAP09(f, __VA_ARGS__))
#define _PP_MAP11(f, x, ...) f(x) _PP_EVAL(_PP_MAP10(f, __VA_ARGS__))
#define _PP_MAP12(f, x, ...) f(x) _PP_EVAL(_PP_MAP11(f, __VA_ARGS__))
#define _PP_MAP13(f, x, ...) f(x) _PP_EVAL(_PP_MAP12(f, __VA_ARGS__))
#define _PP_MAP14(f, x, ...) f(x) _PP_EVAL(_PP_MAP13(f, __VA_ARGS__))
#define _PP_MAP15(f, x, ...) f(x) _PP_EVAL(_PP_MAP14(f, __VA_ARGS__))
#define _PP_MAP16(f, x, ...) f(x) _PP_EVAL(_PP_MAP15(f, __VA_ARGS__))
#define _PP_MAP17(f, x, ...) f(x) _PP_EVAL(_PP_MAP16(f, __VA_ARGS__))
#define _PP_MAP18(f, x, ...) f(x) _PP_EVAL(_PP_MAP17(f, __VA_ARGS__))
#define _PP_MAP19(f, x, ...) f(x) _PP_EVAL(_PP_MAP18(f, __VA_ARGS__))
#define _PP_MAP20(f, x, ...) f(x) _PP_EVAL(_PP_MAP19(f, __VA_ARGS__))
#define _PP_MAP21(f, x, ...) f(x) _PP_EVAL(_PP_MAP20(f, __VA_ARGS__))
#define _PP_MAP22(f, x, ...) f(x) _PP_EVAL(_PP_MAP21(f, __VA_ARGS__))
#define _PP_MAP23(f, x, ...) f(x) _PP_EVAL(_PP_MAP22(f, __VA_ARGS__))
#define _PP_MAP24(f, x, ...) f(x) _PP_EVAL(_PP_MAP23(f, __VA_ARGS__))
#define _PP_MAP25(f, x, ...) f(x) _PP_EVAL(_PP_MAP24(f, __VA_ARGS__))
#define _PP_MAP26(f, x, ...) f(x) _PP_EVAL(_PP_MAP25(f, __VA_ARGS__))
#define _PP_MAP27(f, x, ...) f(x) _PP_EVAL(_PP_MAP26(f, __VA_ARGS__))
#define _PP_MAP28(f, x, ...) f(x) _PP_EVAL(_PP_MAP27(f, __VA_ARGS__))
#define _PP_MAP29(f, x, ...) f(x) _PP_EVAL(_PP_MAP28(f, __VA_ARGS__))
#define _PP_MAP30(f, x, ...) f(x) _PP_EVAL(_PP_MAP29(f, __VA_ARGS__))
#define _PP_MAP31(f, x, ...) f(x) _PP_EVAL(_PP_MAP30(f, __VA_ARGS__))
#define _PP_MAP32(f, x, ...) f(x) _PP_EVAL(_PP_MAP31(f, __VA_ARGS__))
#define _PP_MAP33(f, x, ...) f(x) _PP_EVAL(_PP_MAP32(f, __VA_ARGS__))
#define _PP_MAP34(f, x, ...) f(x) _PP_EVAL(_PP_MAP33(f, __VA_ARGS__))
#define _PP_MAP35(f, x, ...) f(x) _PP_EVAL(_PP_MAP34(f, __VA_ARGS__))
#define _PP_MAP36(f, x, ...) f(x) _PP_EVAL(_PP_MAP35(f, __VA_ARGS__))
#define _PP_MAP37(f, x, ...) f(x) _PP_EVAL(_PP_MAP36(f, __VA_ARGS__))
#define _PP_MAP38(f, x, ...) f(x) _PP_EVAL(_PP_MAP37(f, __VA_ARGS__))
#define _PP_MAP39(f, x, ...) f(x) _PP_EVAL(_PP_MAP38(f, __VA_ARGS__))
#define _PP_MAP40(f, x, ...) f(x) _PP_EVAL(_PP_MAP39(f, __VA_ARGS__))
#define _PP_MAP41(f, x, ...) f(x) _PP_EVAL(_PP_MAP40(f, __VA_ARGS__))
#define _PP_MAP42(f, x, ...) f(x) _PP_EVAL(_PP_MAP41(f, __VA_ARGS__))
#define _PP_MAP43(f, x, ...) f(x) _PP_EVAL(_PP_MAP42(f, __VA_ARGS__))
#define _PP_MAP44(f, x, ...) f(x) _PP_EVAL(_PP_MAP43(f, __VA_ARGS__))
#define _PP_MAP45(f, x, ...) f(x) _PP_EVAL(_PP_MAP44(f, __VA_ARGS__))
#define _PP_MAP46(f, x, ...) f(x) _PP_EVAL(_PP_MAP45(f, __VA_ARGS__))
#define _PP_MAP47(f, x, ...) f(x) _PP_EVAL(_PP_MAP46(f, __VA_ARGS__))
#define _PP_MAP48(f, x, ...) f(x) _PP_EVAL(_PP_MAP47(f, __VA_ARGS__))
#define _PP_MAP49(f, x, ...) f(x) _PP_EVAL(_PP_MAP48(f, __VA_ARGS__))
#define _PP_MAP50(f, x, ...) f(x) _PP_EVAL(_PP_MAP49(f, __VA_ARGS__))
#define _PP_MAP51(f, x, ...) f(x) _PP_EVAL(_PP_MAP50(f, __VA_ARGS__))
#define _PP_MAP52(f, x, ...) f(x) _PP_EVAL(_PP_MAP51(f, __VA_ARGS__))
#define _PP_MAP53(f, x, ...) f(x) _PP_EVAL(_PP_MAP52(f, __VA_ARGS__))
#define _PP_MAP54(f, x, ...) f(x) _PP_EVAL(_PP_MAP53(f, __VA_ARGS__))
#define _PP_MAP55(f, x, ...) f(x) _PP_EVAL(_PP_MAP54(f, __VA_ARGS__))
#define _PP_MAP56(f, x, ...) f(x) _PP_EVAL(_PP_MAP55(f, __VA_ARGS__))
#define _PP_MAP57(f, x, ...) f(x) _PP_EVAL(_PP_MAP56(f, __VA_ARGS__))
#define _PP_MAP58(f, x, ...) f(x) _PP_EVAL(_PP_MAP57(f, __VA_ARGS__))
#define _PP_MAP59(f, x, ...) f(x) _PP_EVAL(_PP_MAP58(f, __VA_ARGS__))
#define _PP_MAP60(f, x, ...) f(x) _PP_EVAL(_PP_MAP59(f, __VA_ARGS__))
#define _PP_MAP61(f, x, ...) f(x) _PP_EVAL(_PP_MAP60(f, __VA_ARGS__))
#define _PP_MAP62(f, x, ...) f(x) _PP_EVAL(_PP_MAP61(f, __VA_ARGS__))
#define _PP_MAP63(f, x, ...) f(x) _PP_EVAL(_PP_MAP62(f, __VA_ARGS__))
#define _PP_MAP64(f, x, ...) f(x) _PP_EVAL(_PP_MAP63(f, __VA_ARGS__))

#define _PP_GET_NTH_ARG( \
  _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
  _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
  _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
  _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
  _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
  _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
  _61, _62, _63, _64, N, ...) N

#define _PP_MAP(f, ...) _PP_EVAL(_PP_EVAL(_PP_GET_NTH_ARG(__VA_ARGS__, \
  _PP_MAP64, _PP_MAP63, _PP_MAP62, _PP_MAP61, \
  _PP_MAP60, _PP_MAP59, _PP_MAP58, _PP_MAP57, _PP_MAP56, \
  _PP_MAP55, _PP_MAP54, _PP_MAP53, _PP_MAP52, _PP_MAP51, \
  _PP_MAP50, _PP_MAP49, _PP_MAP48, _PP_MAP47, _PP_MAP46, \
  _PP_MAP45, _PP_MAP44, _PP_MAP43, _PP_MAP42, _PP_MAP41, \
  _PP_MAP40, _PP_MAP39, _PP_MAP38, _PP_MAP37, _PP_MAP36, \
  _PP_MAP35, _PP_MAP34, _PP_MAP33, _PP_MAP32, _PP_MAP31, \
  _PP_MAP30, _PP_MAP29, _PP_MAP28, _PP_MAP27, _PP_MAP26, \
  _PP_MAP25, _PP_MAP24, _PP_MAP23, _PP_MAP22, _PP_MAP21, \
  _PP_MAP20, _PP_MAP19, _PP_MAP18, _PP_MAP17, _PP_MAP16, \
  _PP_MAP15, _PP_MAP14, _PP_MAP13, _PP_MAP12, _PP_MAP11, \
  _PP_MAP10, _PP_MAP09, _PP_MAP08, _PP_MAP07, _PP_MAP06, \
  _PP_MAP05, _PP_MAP04, _PP_MAP03, _PP_MAP02, _PP_MAP01 \
  ))(f, __VA_ARGS__))

#if REFLECTION_WITH_FIELD_NAME
#define _PP_REFLECTION_FIELD_NAME(x) _PP_STR(_PP_EVAL(x))
#else
#define _PP_REFLECTION_FIELD_NAME(x) ""
#endif

#define _PP_REFLECTION_ALL(x) _PP_EVAL x
#define _PP_REFLECTION_SECOND(x) _PP_EAT x
#define _PP_REFLECTION_FIELD(x) _PP_REFLECTION_ALL(x);
#define _PP_REFLECTION_METHOD2(x) v(this, _PP_REFLECTION_FIELD_NAME(x), x);
#define _PP_REFLECTION_METHOD(x) _PP_REFLECTION_METHOD2(_PP_REFLECTION_SECOND(x))

#define _PP_REFLECTION_VISTOR_METHOD(type, ...) \
  template <class Vistor> \
  void _reflect(Vistor& v) type { \
    _PP_MAP(_PP_REFLECTION_METHOD, __VA_ARGS__) \
  }

#define REFLECT(...) \
  _PP_MAP(_PP_REFLECTION_FIELD, __VA_ARGS__) \
  _PP_REFLECTION_VISTOR_METHOD(_PP_EMPTY, __VA_ARGS__) \
  _PP_REFLECTION_VISTOR_METHOD(const, __VA_ARGS__)


// Usage of REFLECT()

#define OBJECT_NAME_METHOD(obj) \
  static const char* object_name() { \
    return #obj; \
  }

struct Demo
{
  OBJECT_NAME_METHOD(Demo)

  REFLECT(
    (int) a,
    (int) b,
    (std::string) c
  )

  int d; // DO NOT REFLECT
};

struct Amplifier {
  template <class Obj>
  void apply(Obj* obj) {
    obj->_reflect(*this);
  }

  template <class Obj, class Field>
  void operator() (Obj* /*obj*/, const char* /*name*/, Field& field) {
    field *= 100;
  }

  template <class Obj>
  void operator() (Obj* /*obj*/, const char* /*name*/, std::string& field) {
    field += "00";
  }
};

struct Printer {
  template <class Obj>
  void print(const Obj& obj) {
    obj._reflect(*this);
  }

  template <class Obj, class Field>
  void operator() (Obj* obj, const char* name, const Field& field) {
    std::cout << obj->object_name() << "."
      << name << ": " << field << std::endl;
  }
};

int main() {
  Demo a = {100, 200, "300", 400};

  Amplifier amplifier;
  amplifier.apply(&a);

  Printer printer;
  printer.print(a);
}

/*
Output:
Demo.a: 10000
Demo.b: 20000
Demo.c: 30000
*/

BTW, the following code is used for generating all _PP_MAP_? macros (written in JS, so you can run it in web browser).

(function() {
  const maxNumOfEle = 64;
  const mapNamePrefix = '_PP_MAP';
  let codeText = '';

  function formatNumWidth(num) {
    return ("0" + num).slice(-2);
  }

  function AddNewLine() {
    if (codeText.slice(-1) != ' ') {
      codeText += ' ';
    }

    codeText += '\\\n';
    codeText += ' '.repeat(2);
  }

  codeText += `#define ${mapNamePrefix}${formatNumWidth(1)}(f, x) f(x)\n`;
  for (let i = 2; i <= maxNumOfEle; ++i) {
    let funId = formatNumWidth(i);
    codeText += `#define ${mapNamePrefix}${funId}(f, x, ...) f(x)`;

    let nextFunId = formatNumWidth(i - 1);
    codeText += ' _PP_EVAL(';
    codeText += `${mapNamePrefix}${nextFunId}(f, __VA_ARGS__)`;
    codeText += ')';

    codeText += '\n';
  }

  codeText += '\n#define _PP_GET_NTH_ARG(';
  AddNewLine();
  for (let i = 1; i <= maxNumOfEle; ++i) {
    codeText += `_${i}, `;
    if ((i % 10) == 0) {
      AddNewLine();
    }
  }
  codeText += 'N, ...) N\n';

  codeText += `\n#define ${mapNamePrefix}(f, ...) `;
  codeText += '_PP_EVAL(_PP_EVAL(_PP_GET_NTH_ARG(__VA_ARGS__,';
  AddNewLine();
  for (let i = maxNumOfEle; i >= 1; --i) {
    let funId = formatNumWidth(i);
    codeText += `${mapNamePrefix}${funId}`;
    if (i != 1) {
      codeText += ', ';
    }

    if ((i % 5) == 1) {
      AddNewLine();
    }
  }
  codeText += '))(f, __VA_ARGS__))\n';

  console.log(codeText);
})();
Pamela
  • 549
  • 4
  • 7