billyquith / ponder

C++ reflection library with Lua binding, and JSON and XML serialisation.
http://billyquith.github.io/ponder/
Other
647 stars 96 forks source link

Interest for registration of template types? #111

Closed lhamot closed 5 years ago

lhamot commented 5 years ago

Hi! Let's say I have this kind of code to reflect with ponder:

template<typename T>
struct TmplStruct{
    T field1;
};
struct UseTmplStruct{
    TmplStruct<int> tmplField;
};

I wrote a macro to register template type with one template parameter:

#define PONDER_AUTO_TYPE_TMPL1(TYPE, REGISTER_FN) \
    namespace ponder { \
        namespace detail { \
            template <typename T1> struct StaticTypeId<TYPE<T1> > { \
                static const char* get(bool checkRegister = true) { \
                    static char name[256]; \
                    snprintf(name, 256, "%s<%s>", #TYPE, typeid(T1).name()); \
                    if (checkRegister) \
                        detail::ensureTypeRegistered(name, REGISTER_FN<T1>); \
                    return name; \
                } \
                static constexpr bool defined = true, copyable = true; \
            }; \
        } \
    }

The reflection is done with this code:

PONDER_AUTO_TYPE_TMPL1(TmplStruct, declare_TmplStruct);
template<typename T1>
static void declare_TmplStruct(){
    ponder::Class::declare<TmplStruct<T1> >()
        .property("field1", &TmplStruct<T1>::field1);
}

PONDER_AUTO_TYPE(UseTmplStruct, declare_UseTmplStruct);
static void declare_UseTmplStruct(){
    ponder::Class::declare<UseTmplStruct>()
        .property("tmplField", &UseTmplStruct::tmplField);
}

This allow me to use this type in this way:

UseTmplStruct useTmpl;
ponder::UserObject useTmplR(&useTmpl);
useTmplR.set("tmplField", NS::TmplStruct<int>{12});

So, the questions are:

billyquith commented 5 years ago

You can use PONDER_TYPE() for this purpose. You have to explicitly declare the type. There is no "auto" version. This macro works with any number of parameters.

I could perhaps make this more prominent in the docs.

lhamot commented 5 years ago

Thank you for your answer.

With PONDER_TYPE(), I have to call it once by concrete type, isn't it? For example:

PONDER_TYPE(TmplStruct<int>);
PONDER_TYPE(TmplStruct<short>);
PONDER_TYPE(TmplStruct<bool>);
// Have to explicitely call :
static void declare_TmplStruct(){
    ponder::Class::declare<TmplStruct<int> >()
        .property("field1", &TmplStruct<int>::field1);
    ponder::Class::declare<TmplStruct<short> >()
        .property("field1", &TmplStruct<short>::field1);
    ponder::Class::declare<TmplStruct<bool> >()
        .property("field1", &TmplStruct<bool>::field1);
}

Is there an other way to use PONDER_TYPE ?

What I am looking for is a way to avoid to declare each concrete types. Types which are referenced from a .property call could be automatically declared, I guess. Anyway, I will look at the doc carefully.

billyquith commented 5 years ago

Yes, as it stands you'd have to register once for each template instance, because each instance is a different type. I'm reluctant to add macros to the API to solve this because they would only solve one particular problem, and there are many ways in which templates could be used. Also, I don't really like macros because they make code opaque.

Another alternative:

PONDER_TYPE(TmplStruct<int>);
PONDER_TYPE(TmplStruct<short>);
PONDER_TYPE(TmplStruct<bool>);

template <typename T>
static void declare_TmplStruct() {
    ponder::Class::declare<TmplStruct<T> >()
        .property("field1", &TmplStruct<T>::field1);
}

static declare() {
    declare_TmplStruct<int>();
    declare_TmplStruct<short>();
    declare_TmplStruct<bool>();
}

Ideally I'd like to keep the API as simple as possible. I could add more examples like this to the docs.

billyquith commented 5 years ago

I added an example in the docs. I'll close this unless there are further questions.