dimanche 18 février 2018

Forward parameter pack to pointer function (unknown types)

I am trying to write an es6 Promise-like class for c++ without the use of an external library (in my project I can't use boost or the std lib).

I am having troubles handling the callback that's supposed to process a resolved or rejected promise. Because I want to chain different resolved value types, I can't specify the type.

I have 2 classes that handle the promise. Defer is used to resolve a value or reject the promise, and Promise is used to chain the callback functions (promises). I have omitted some code for readability.

Defer class:

class Defer
{
public:
    Defer(Promise *promise) : Defer(promise, NULL, NULL) {};
    Defer(Promise *promise, static_deferred_callback<> onResolved) : Defer(promise, onResolved, NULL) {};
    Defer(Promise *promise, static_deferred_callback<> onResolved, static_defered_callback<> onRejected) : 
        promise(promise), 
        onResolved(onResolved), 
        onRejected(onRejected) {};
    virtual ~Defer() { };

    template <typename ...Args>
    inline void resolve(Args&&... args)
    {   
        if (onResolved)
        {
            ((static_deferred_callback<Args...>)onResolved)(promise, args...);
        }
    };

    // inline void resolve(Promise<T> &p); continue chain w/ new promise

    inline void reject()
    {
        if (onRejected)
        {
            onRejected(promise);
        }
    };

private:
    Promise *promise;

    static_deferred_callback<> onResolved = 0;
    static_deferred_callback<> onRejected = 0;
};

Promise class:

class Promise
{
public:
    Promise(new_promise promise) : defer(new Defer(this, Promise::OnPromiseResolved<>)), size(0), currentIndex(0)
    {
        this->promised = promise;
    };
    virtual ~Promise() { };

    /* ... */

    inline Promise& run()
    {
        if (!hasRun && promised)
        {
            hasRun = true;

            Defer d = *defer;
            promised(d);
        }

        return *this;
    };

private:

    template <typename ...Args>
    static deferred_callback<Args...> OnPromiseResolved(Promise *promise, Args&&... x)
    {
        // problem lies here,
        // param 'x' yields no values at this point.

        // if (promise && !promise->rejected)
        // {
        //     promise->next(x...);
        // }
    };

    template <typename ...Args>
    static deferred_callback<Args...> OnPromiseRejected(Promise *promise, Args... x)
    {
        if (promise && !promise->rejected)
        {
            promise->rejected = true;

            promise->onFailed();
        }
    };

    template <typename ...Args>
    inline void call(next_promise<Args...> promise, Args &&... x)
    {
        if (promise)
        {
            Defer d = *defer;
            promise(d, x...);
        }
    };

    template <typename ...Args>
    inline void next(Args &&... x)
    {
        if (!isFinished && (currentIndex == size || rejected))
        {
            isFinished = true;

            if (!rejected && onSuccess)
            {
                onSuccess(x...);
            }

            if (onAlways)
            {
                onAlways(rejected, x...);
            }
        }

        if (!rejected && currentIndex < size)
        {
            call(chain[currentIndex++], x...);
        }
    };

    bool rejected = false;
    bool hasRun = false;
    bool isFinished = false;

    new_promise promised;

    next_promise<> chain[64]; // temporary fixed size

    resolved_function<> onSuccess = 0;
    anonymous_function onFailed = 0; 
    finished_promise<> onAlways = 0;

    size_t size;
    size_t currentIndex;

    Defer *defer;
};

type defs:

using new_promise = void (*)(Defer);

template <typename ...Args>
using next_promise = void (*)(Defer, Args...);

template <typename ...Args>
using resolved_promise = void (*)(Args...);

template <typename ...Args>
using finished_promise = void (*)(bool, Args...);

template <typename ...Args>
using deferred_callback = void (*)(Promise*, Args...);

template <typename ...Args>
using static_deferred_callback = void (* (*)(Promise*, Args...))(Promise*, Args...);

At the moment the type definitions are a total mess. I am using multiple type definitions to specify the type of callback functions I need for my Promise implementation.

Sample usage:

int main()
{
    Promise promise = Promise([](Defer defer) {
        defer.resolve(11, 22, 33);
    })
    // .then([](Defer defer, int a, int b, int c) {
    //     defer.resolve(a + b + c);
    // })
    .run();

    return 0;
}

The problem I have with the above is that the function specified to handle the resolved state (Promise::OnPromiseResolved) must accept any type (template <...Args>). I can resolve any and multiple values from the returned Defer object (Defer::resolve). When I call the resolve method on the Defer object, the values are passed on. Next I want to send those values over to the Promise object I have stored in the Defer object. However, it seems like when I call the pointer to a function (onResolved) in the Defer class, the pack expansion expression does not forward the values onto the callback when the type is any.

If I explicitly set it to the type I am resolving in the specified callback function, I can retrieve the values I have passed through using the resolve method of the Defer object (e.g. I resolve 2 integers, the params of the method OnPromiseResolved in the Promise class would be 2 integers). But this makes it impossible to have the resolvable types to be any.

If any of this didn't make too much sense, please don't hesitate to ask for more clarification.

Aucun commentaire:

Enregistrer un commentaire