Home > Blockchain >  C 20 Constraints - Restrict typename TFunction to be a function (with certain signature)
C 20 Constraints - Restrict typename TFunction to be a function (with certain signature)

Time:06-22

How to translate this TS Code into modern C 20 using lambdas and modern templating features?

[Edit]: The main question here is: How to restrict typename TFunction to be of type Function or even a more specific function with a given signuature?

interface Subscription<TFunction extends Function> {
  readonly subscriber: TFunction;
  unsubscribe();
}

class Subscriptions<TFunction extends Function = Function> {

  private _subscriptions: Subscription<TFunction>[] = [];

  subscribe(f: TFunction): Subscription<TFunction> {
    // ...
    const _subscription: Subscription<TFunction> = {
      subscriber: f,
      unsubscribe: () => {
        this._subscriptions = this._subscriptions.filter(s => s !== f);
      };
    };
    this._subscriptions = [...this._subscriptions, _subscription];
    return _subscription;
  }
}

CodePudding user response:

Function types in C are expressed as types like R(Arg1, Arg2, Arg3) (denoting a function that takes three arguments of types Arg1, Arg2, Arg3 and returns an R). You can take a pointer to such a function, which has the type R(*)(Arg1, Arg2, Arg3).

A template will typically use one type parameter for R and a parameter pack to generalise over all parameter types, e.g. template <typename R, typename... Args> /* something involving the type R(Args...) */

If you want to include objects with appropriate operator() (especially lambdas), you can use std::function<R(Args...)> to type erase the specific type of each subscriber.

Something like

template <typename Sig>
struct Subscription
{
    std::function<Sig> subscription;
    void unsubscribe();
};

template <typename R, typename... Args>
class Subscriptions
{
    std::vector<Subscription<R(Args...)>> subscriptions;
public:
    R notify(Args... args)
    {
        R result;
        for (auto & s : subscriptions) result  = s.subscription(args...);
        return result;
    }
    Subscription<R(Args...)> subscribe(std::function<R(Args...)> s);
};

Because you have to be explicit about object lifetimes in C , lambda captures are more complex, so the implementation of unsubscribe is going to be tricky, in particular std::function<Sig> is not equality comparable with itself.

  • Related