billyquith / ponder

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

Creating UserObject via class name does not work #108

Closed shierei closed 5 years ago

shierei commented 5 years ago

When you declare a metaclass, you can give it a name. This name however cannot be used to retrieve the metaclass back using ponder::classByName(). The name given has to be either an empty string or the same as the C++ class type name. I think this is a major usage problem for reflection purposes.

billyquith commented 5 years ago

Do you have an example of this failing please? The unit tests seem to work: https://github.com/billyquith/ponder/blob/master/test/ponder/class.cpp

shierei commented 5 years ago

simple.cpp.txt

Attached please see a modified test/exampels/simple.cpp. The key is to give the name of metaclass that is not the same as the metaclass's C++ type name. For example, in this example I gave the name of the Person metaclass "People". After you re-make simple.cpp and run it, you should see the following exception raised.

test/examples/simple.cpp:112: FAILED: due to unexpected exception with message: the metaclass Person couldn't be found

billyquith commented 5 years ago

simple.cpp.txt:

#include "test.hpp"

//! [eg_simple]

#include <ponder/classbuilder.hpp>
#include <ponder/uses/runtime.hpp>
#include <iostream>

//! [eg_simple_class]
class Person
{
public:
     // constructor
    Person(const std::string& name)
        : m_name(name)
    {}

    // accessors for private members
    std::string name() const { return m_name; }
    void setName(const std::string& name) { m_name = name; }

    // public members
    float height;
    unsigned int shoeSize;

    // member function
    bool hasBigFeet() const { return shoeSize > 10; } // U.K.!

private:
    std::string m_name;
};
//! [eg_simple_class]

//! [eg_simple_declare]
PONDER_TYPE(Person)     // declare the type to Ponder

static void declare()   // declare the class members to Ponder
{
    ponder::Class::declare<Person>("People")
        .constructor<std::string>()
        .property("name", &Person::name, &Person::setName)
        .property("height", &Person::height)
        .property("shoeSize", &Person::shoeSize)
        .function("hasBigFeet", &Person::hasBigFeet)
        ;
}
//! [eg_simple_declare]

//! [eg_simple_use]
// An example of how you might use Ponder:
static void use()
{
    //! [eg_simple_metaclass]
    // retrieve the metaclass (containing the member data)
  const ponder::Class& metaclass = ponder::classByName("People");
    //! [eg_simple_metaclass]

    //! [eg_simple_create]
    // construct a new person
    ponder::UserObject person = ponder::runtime::create(metaclass, "Bozo");
    //! [eg_simple_create]

    // set attributes
    person.set("height", 1.62f);
    person.set("shoeSize", 28);

    // retrieve a function we would like to call
    const auto& func = metaclass.function("hasBigFeet");

    // call the function and get the result
    const bool bigFeet = ponder::runtime::call(func, person).to<bool>();

    // nasty
    //! [eg_simple_destroy]
    ponder::runtime::destroy(person);
    //! [eg_simple_destroy]
}
//! [eg_simple_use]

//! [eg_simple]
billyquith commented 5 years ago

Ok, yes this needs some work.

billyquith commented 5 years ago
    return UserObject(&classByObject(object), new Holder(RefTraits::getPointer(object)));

from UserObject UserObject::makeRef(T& object) is the problem. classByName() isn't the problem, it is makeRef() trying to get the metaclass details via the object type, which is different. Probably best to look up everything by type (id) and map the names instead. This could mean substantial changes to the registration/declaration.