// Create class members and methods with X-Macros
// Klaus Warnke

#include <string>
#include <tuple>
#include <iostream>
#include <cassert>

#define MEMBER_TBL                        \
    /*type        ,name ,default*/        \
    X(int         ,_(i) ,42     )         \
    X(float       ,_(f) ,3.14   )         \
    X(std::string ,  t  ,"Hello")         \

struct Foo
{
#define _(x) x
#define X(type, name, default) type name{default};
    MEMBER_TBL
#undef X
#undef _

    bool operator==(Foo const& other) const {
        return  std::tie(
#define _(x) x,
#define X(type, name, default) this->name
            MEMBER_TBL
#undef X
        ) == std::tie(
#define X(type, name, default) other.name
            MEMBER_TBL
#undef X
#undef _
        );
    }

    void print() const { 
#define STR(x) #x
#define _(x) x
#define X(type, name, default)            \
        std::cout <<                      \
            STR(name) << ": " << name << " ";
        MEMBER_TBL
#undef X
#undef _
#undef STR
        std::cout << std::endl;
    }
};

#undef _
#undef MEMBER_TBL

int main(void) 
{
    Foo foo{}, bar{};
    
    assert(foo == bar);
    bar.t = "bye";
    assert(! (foo == bar));

    foo.print(); // i: 42 f: 3.14 t: Hello 
    bar.print(); // i: 42 f: 3.14 t: bye 

    return 0;
}
