Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Fun times with C++ reflection and tuples  (Read 10005 times)

0 Members and 1 Guest are viewing this topic.

foobarbaz

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Fun times with C++ reflection and tuples
« on: February 25, 2014, 06:52:46 am »
Hey guys, I scourged the interwebs today stealing everybody's code and put this little demo together.

The whole system is based off of C++11's std::tuple.

What started this furious rampage was me trying to get automatic serialization that could go beyond primitive types. I want to have custom encoding for custom objects. Until C++10923812093809 whatever comes out with compile-time reflection, I made this. Lemme know what you guys think (i.e. probably its complete garbage).

Link: https://github.com/tedsta/Reflectable

I stole code from these places so far:

http://stackoverflow.com/a/13066078
http://stackoverflow.com/a/6894436

Check the readme for some benchmarks. Don't know exactly what those compiler optimizations do.

ChronicRat

  • Sr. Member
  • ****
  • Posts: 327
  • C++ programmer
    • View Profile
    • My blog
Re: Fun times with C++ reflection and tuples
« Reply #1 on: February 25, 2014, 07:04:00 am »
Pythonistas, get your hands off from C++!!!  :)

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: Fun times with C++ reflection and tuples
« Reply #2 on: February 25, 2014, 09:00:21 am »
How does the final user code look? Can you show a short example? Usually, the problem with tuples is that access to them leads to non-expressive or at least cumbersome code (even with tags).

You might be interested in my project Aurora, especially the Tuple metaprogramming file and the Named Tuple macros :)
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

foobarbaz

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: Fun times with C++ reflection and tuples
« Reply #3 on: February 25, 2014, 07:21:04 pm »
Pythonistas, get your hands off from C++!!!  :)

Hehe it doesn't hurt performance the way python does I promise!

You might be interested in my project Aurora, especially the Tuple metaprogramming file and the Named Tuple macros :)

Your Aurora NamedTuple looks pretty cool. If you can iterate over those members (even if it's at compile time with recursive templates), then that's exactly what I want. Is that possible?

I just threw this together for fun, I don't really think it's usable yet, but maybe it could be prettied up with some macros :P Also, without the compiler optimizations, the low performance scares me.

Here's some classes:
struct Foo
{
    std::string str;
    int i;
};

std::ostream& operator<<(std::ostream& left, const Foo& right)
{
    return left << "str: " << right.str << ", " << "i: " << right.i;
}

struct Test : public Reflectable<struct name,      std::string,
                                 struct health,    int,
                                 struct foo,       Foo>
{
};
 

And a little sample processor to iterate through members:

class SamplePrinter
{
    public:
        /// \brief Int serialization
        void operator () (int x)
        {
            std::cout << "int: " << x << std::endl;
        }

        /// \brief Float serialization
        void operator () (float x)
        {
            std::cout << "float: " << x << std::endl;
        }

        /// \brief Double serialization
        void operator () (double x)
        {
            std::cout << "double: " << x << std::endl;
        }

        /// \brief String serialization
        void operator () (const std::string& x)
        {
            std::cout << "string: " << x << std::endl;
        }

        /// \brief The generic case
        template <typename X>
        void operator () (const X& x)
        {
            std::cout << "other: " << x << std::endl;
        }

    private:
};
 

And Using the stuff
Test test;
test.get<name>() = "bob";
test.get<health>() = 42;
test.get<foo>().str = "hello";
test.get<foo>().i = 24;

test.iterate(SamplePrinter());
 

I'm also pondering how you could make a macro to automatically set up references to the tuple members as public member variables, allowing you to access the variables with regular syntax. The benchmark shows that reference access is a little slower than regular tuple access with compiler optimizations on, though.
« Last Edit: February 25, 2014, 08:55:29 pm by tedsta »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: Fun times with C++ reflection and tuples
« Reply #4 on: February 25, 2014, 08:39:15 pm »
You're Aurora NamedTuple looks pretty cool. If you can iterate over those members (even if it's at compile time with recursive templates), then that's exactly what I want. Is that possible?
Sure 8)

Since every named tuple in Aurora contains a toStdTuple() member function, you can do with it anything you can do with std::tuple. That's the primary power behind it: expressive and intuitive syntax and all the nice standard tuple features.

But it's also possible to write a direct serializer. Like this, you don't have to create a temporary tuple, and you can output the member's actual names! It requires a bit of preprocessor magic, though.
#include <Aurora/Tools/NamedTuple.hpp>
#include <iostream>
#include <string>

// Preprocessor macro to output one member (the helpers are required because the
// AURORA_PP_FOREACH metafunction has a different signature
#define SERIALIZE_MEMBER_TV(Type, var)  out << AURORA_PP_STRINGIZE(var) << ": " << var << "\n";
#define SERIALIZE_MEMBER_P(pair)        SERIALIZE_MEMBER_TV pair
#define SERIALIZE_MEMBER(pair, index)   SERIALIZE_MEMBER_P(pair)

// Preprocessor macro to output all members using iteration through typeVarPairs
#define SERIALIZER(TupleName, typeVarPairs)             \
void serialize(std::ostream& out) const                 \
{                                                       \
    AURORA_PP_FOREACH(SERIALIZE_MEMBER, typeVarPairs)   \
}


// Declare named tuple
AURORA_NAMED_TUPLE_EXT(MyTuple,
(                                   // This is the list
    (std::string, name),            // of member variable
    (int, health)                   // declarations
),                                  //
(                                   // This is the list of
    SERIALIZER                      // extensions (only 1)
))

int main()
{
    MyTuple tuple("monster", 42);
    tuple.serialize(std::cout);
}

Output:
name: monster
health: 42

Beautiful, isn't it? :P
Have a look at the documentation to learn about the involved preprocessor metafunctions. The number of arguments is currently limited to 5, but I can increase that.
« Last Edit: February 25, 2014, 08:56:32 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

foobarbaz

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: Fun times with C++ reflection and tuples
« Reply #5 on: February 25, 2014, 09:26:19 pm »
It is pretty beautiful. Sweet. I really wish C++ supported real compile-time reflection on regular objects. Although, I know D already does :P

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: Fun times with C++ reflection and tuples
« Reply #6 on: February 25, 2014, 09:47:29 pm »
Yes, sometimes it's a pity that things are difficult to achieve natively. But at least C++ is so powerful that a lot of language features can be emulated within the language itself. The Boost libraries are extreme in this respect: Foreach, Lambda, Move, Parameter, ...

By the way, if you use this serialization in multiple places, don't hesitate to make it more user-friendly by putting all the preprocessor stuff in a header and defining a wrapper macro:
#define SERIALIZABLE_TUPLE(TupleName, typeVarPairs) \
    AURORA_NAMED_TUPLE_EXT(TupleName, typeVarPairs, (SERIALIZER))
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

 

anything