vendredi 11 janvier 2019

Is the following C++ reflection framework fully standard compliant or am i using undefined behavior?

I am concerned about the following framework, especially the magic inside the register_property_ helper classes which determines the pointer to an embedding object instance when given a pointer to one of its members. Does this implementation use undefined behavior? If so, how could i rewrite the implementation to be fully standard compliant?

#include <any>
#include <map>
#include <iostream>
#include <memory>
#include <string>

// FRAMEWORK

class object
{
public:
    std::any& operator[] (std::string name) { return *_properties.at (name); }
    std::any const& operator[] (std::string name) const { return *_properties.at (name); }

protected:
    void register_property (std::string name, std::any& property)
    {
        _properties[name] = std::addressof (property);
    }

private:
    std::map<std::string, std::any*> _properties;
};

#define REGISTER_PROPERTY(name, member) \
struct register_property_ ## name \
{ \
    register_property_ ## name () { self ()->register_property (# name, self ()->member); } \
    register_property_ ## name (register_property_ ## name const&) { self ()->register_property (# name, self ()->member); } \
    register_property_ ## name& operator= (register_property_ ## name const&) = default; \
    register_property_ ## name (register_property_ ## name &&) { self ()->register_property (# name, self ()->member); } \
    register_property_ ## name& operator= (register_property_ ## name &&) = default; \
\
private: \
    self_type* self () \
    { \
        return reinterpret_cast<self_type*> (reinterpret_cast<std::byte*> (this) - offset_to_self ()); \
    } \
    static ptrdiff_t offset_to_self (self_type* ptr = nullptr) \
    { \
        return reinterpret_cast<ptrdiff_t> (std::addressof (ptr->register_property_ ## name ## _)) - reinterpret_cast<ptrdiff_t> (ptr); \
    } \
} register_property_ ## name ## _

// CLIENT USE CASE

auto make_unique_object () -> std::unique_ptr<object>
{
    class foo_object
        : public object
    {
        std::any _width;
        std::any _height;

        using self_type = foo_object;
        REGISTER_PROPERTY(Width, _width);
        REGISTER_PROPERTY(Height, _height);
    };

    return std::make_unique<foo_object> ();
}

int main ()
{
    auto object = make_unique_object ();

    (*object)["Height"] = 50;

    std::cout << "Object heigth is " << std::any_cast<int> ((*object)["Height"]) << '\n';
}





Aucun commentaire:

Enregistrer un commentaire