0

I am trying to delegate a method call using a nested std::invoke. Sample code:

class Executor
{
public:
    bool Execute(bool someFlag);
};

template <class TMemberFunction, class TInstance, typename TResponse>
class Invoker
{
public:
    TResponse Invoke(TMemberFunction* function, TInstance* instance, bool someFlag) {
        return std::invoke(function, instance, someFlag);
    }
};

void Main()
{
    // Create an executor
    Executor executor;
    bool someFlag = true;

    // How can I pass the member function type here?
    Invoker<???, Executor, bool> invoker;
    // Invoke member method
    bool response = invoker.Invoke(&Executor::Execute, &executor, someFlag);
}

What's the proper way to pass the member function's type to the Invoker template?

Edit: sample code corrections.

pathkon
  • 33
  • 7
  • 1
    Please try to avoid unrelated problems in your [mre], make sure it only describes the problem you ask about. Unrelated errors and problems tend to distract. – Some programmer dude Sep 12 '22 at 09:39
  • 2
    (`Executor executor();` is a function declaration.) – Mat Sep 12 '22 at 09:41
  • As for a possible workaround or solution, why do you need to have the `TMemberFunction` as a template for the *class* instead of the function? If you look at how the standard library handles callable objects, they use only a single template type for the callable object, and only for the function that uses the callable object. Then it's up to the user to make sure it's a proper callable object that is being passed, like a lambda function. – Some programmer dude Sep 12 '22 at 09:41
  • 2
    `Invoker invoker;` but requires other fixes. and might be simplified as `TInstance`, `TResponse` could be deduced from 1st template argument. – Jarod42 Sep 12 '22 at 09:41
  • 1
    `Invoker invoker;` or simply `Invoker invoker;` – stribor14 Sep 12 '22 at 10:04

1 Answers1

2

You might write your Invoker class like:

template <typename TMemberFunction>
class Invoker;

template <class C, typename Ret, typename... Args>
class Invoker<Ret (C::*) (Args...)>
{
public:
    Ret Invoke(Ret (C::*method) (Args...), C* instance, Args... args) {
        return std::invoke(method, instance, std::forward<Args>(args)...);
    }
};

template <class C, typename Ret, typename... Args>
class Invoker<Ret (C::*) (Args...) const>
{
public:
    Ret Invoke(Ret (C::*method) (Args...) const, const C* instance, Args... args) {
        return std::invoke(method, instance, std::forward<Args>(args)...);
    }
};
// other specializations to handle combination of volatile, ref, c-ellipsis

and than use it:

int main()
{
    Executor executor;
    Invoker <bool (Executor::*)(bool)> invoker;
    bool response = invoker.Invoke(&Executor::Execute, &executor, true);
    // ..
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302