Now that your code is public I can give you various minor comments about it
Thank you for your comments! That's exactly what I wanted, especially coming from awesome programmers like you.
It seems like JsonCast.h has found a way into the "include" folder when it should only be in "example"
Fixed!
Also, you shouldn't use #pragma once alone, even if it's supported by all the common compilers that are able to compile your code.
Should I use both pragma once and include guards?
You should include C++-style headers (<cassert> instead of <assert.h>).
Thanks, forgot about that. Fixed.
You should enclose your functions and classes into a namespace. "member" is too common to be left in the global scope.
I have no idea for the namespace yet, any suggestions?
I like the C++14 implementation, it's really small and yet does the job perfectly. The 100% generic approach has some limitations though (ie. how would I get/store/use a single specific MemberPtr?), but you can easily expand this code if your requirements evolve.
Thank you! Yeah, getting/storring specific MemberPtr is not yet possible, but doing some stuff for a single member is possible, like this:
for_tuple([](const auto& memberPtr) {
if (memberPtr.getName() == "someVar") {
// do something for this particular member
}, Meta::getMembers<SomeClass>());
Too bad it works in O(n), though it should be much problem. I wish there was a way to store members not in tuple, but in some unoderder_map like structure, this would make things much easier, but this structure has to be heterogeneous!
And I will surely add some stuff (I've added some neat things today, see below)
it is interesting, i haven't seen alike it before, but what took my attention most is your meta function "for_each_arg". i'm afraid, it is not going to do what it is supposed to do, for some reasons the args order is not guaranteed. probably it will fail if args... is empty. you may take a look to this http://stackoverflow.com/questions/28110699/what-does-this-variadic-template-code-do?answertab=votes#tab-top for more details.
Thanks for you comment. The order is not guaranteed, yep, but VS, GCC and Clang to stuff in order. I realize that this is not guaranteed but at least there's some order for some compilers!
I'll take a look at this later, though. For now you can just think of std::tuple as if it was std::unordered_map with member names as keys.
As for empty Args... see my update below. I've added and overload for empty tuple which takes empty tuple and just does nothing with it. This fixes the problem (unless the user calls for_each_arg... which is not needed!
)
Okay, and now for some new stuff...
(I hope people won't mind me discussing all this stuff in this thread, I wish I could start another thread about this lib, but it's not an SFML Project, so...)
New stuffI've changed getMembers from being a class member function to Meta struct templated function.
I could have made it a free function, but it's hard to make a template specialization a friend, it's much easier to write "friend class Meta" in classes you want to serialize (it's not required most of the time, though)
Template specialization looks like this:
#include <Meta.h>
template <>
inline auto& Meta::getMembers<Person>()
{
static auto memberPtrs = std::make_tuple(
member("someMember", &Class::someMember),
...);
return memberPtrs;
}
This template specialization should be included in header, because compiler can't deduce return type if you then try to use this specialization somewhere else.
I was worried that there would be some problems with mixing static with inline (after all Meta::getMembers<T> is static! And inline! And contains static variable! What if it's copied between translation units?)
Worry not, here's a quote which saved my project!
"[..] An inline function with external linkage shall have the same address in all translation units. A static local variable in an extern inline function always refers to the same object. A string literal in an extern inline function is the same object in different translation units." - [dcl.fct.spec]/4
Cool, so the memberPtrs tuple is created ONCE for each registered type. That's exactly what I want. And here's another cool thing, template function implementation looks like this:
template <typename T>
inline auto& Meta::getMembers()
{
static std::tuple<> emptyTuple;
return emptyTuple;
}
This means that getMembers<Class>() returns empty tuple for all unregistered classes! (Instead of producing compile error)
Not sure that this is expected behaviour, but I've added overload for forTuple which takes empty tuple. This means that if you do this:
orTuple(/* some lambda */, Meta::getMembers<SomeUnregisteredClass>());
then it'll do nothing.
Some questions1) I'm thinking about renaming MemberPtr to just Member. Is this reasonable? After all some MemberPtr's may contain only getter and setter function pointer...
2) Is there some good namespace which I can use for my project? I have no idea for the name yet. Simple "meta" would be nice, but I feel that it's too generic.
3) What should library do in exceptional cases? (he-he)
Should it assert? Should it throw an exception? Here's and example, I want to add a function which would return non-const reference to member. For example:
T& MemberPtr::getNonConstRef(Class& obj);
But this is only possible if MemberPtr contains pointer to member or pointer to non-const getter.
So, what should I do in such case? (there are many cases like that)