vendredi 10 janvier 2020

what is the goal of the code blow in opaque_connection of siglot.h

here comes a trouble to me while I am reading a open source sigslot(http://sigslot.sourceforge.net), there a class named _opaque_connection used to save Class function pointer with Class object pointer , but I don't understand why does it use a union_caster to convert and save function pointer instead of save it directly

here is the code

class _opaque_connection {
private:
    typedef void (*emit_t)(const _opaque_connection*);

    //function pointer convertor
    template <typename FromT, typename ToT>
    union union_caster {
        FromT from;
        ToT to;
    };

    emit_t pemit; 
    has_slots_interface* pdest; 
    unsigned char pmethod[16];

public:
    template <typename DestT, typename... Args>
    _opaque_connection(DestT* pd, void (DestT::*pm)(Args...)) : pdest(pd) {
        typedef void (DestT::*pm_t)(Args...); 
        static_assert(sizeof(pm_t) <= sizeof(pmethod),
                      "Size of slot function pointer too large.");

        typedef void (*em_t)(const _opaque_connection* self, Args...);
        union_caster<em_t, emit_t> caster2; 
        caster2.from = &_opaque_connection::emitter<DestT, Args...>; //why here need to use a caster to convert?
        pemit = caster2.to; //convert it and save function pointer
    }

    has_slots_interface* getdest() const { return pdest; } 
    _opaque_connection duplicate(has_slots_interface* newtarget) const {
        _opaque_connection res = *this;
        res.pdest = newtarget;   
        return res;
    }


    template <typename... Args>
    void emit(Args... args) const {
       typedef void (*em_t)(const _opaque_connection*, Args...);
        union_caster<emit_t, em_t> caster; //then convert it back
        caster.from = pemit;     
        (caster.to)(this, args...); //convert it and use function pointer
    }

private:

    template <typename DestT, typename... Args>
    static void emitter(const _opaque_connection* self, Args... args) {
        typedef void (DestT::*pm_t)(Args...);
        pm_t pm;
        std::memcpy(&pm, self->pmethod, sizeof(pm_t)); 

        (static_cast<DestT*>(self->pdest)->*(pm))(args...); 
    }
};

we can see in _opaque_connection(DestT* pd, void (DestT::*pm)(Args...)) it uses a caster to convert function pointer and assign it to pemit, then connvert it back in void emit(Args... args); why don't make pemit's type as void (em_t)(const _opaque_connection self, Args...);, so it doesn't need any convertions

Aucun commentaire:

Enregistrer un commentaire