0
#include <iostream>
#include <string>

template<typename Func>
class FuncWrapper {
    Func func;
    std::string name;

public:

    FuncWrapper(Func func, std::string name) : func(func), name(std::move(name)) {}

    template<typename ...Args>
    auto operator()(Args ...args) {
        std::cout << "Entering " + name + '\n';
        auto ret = func(args...);
        std::cout << "Exiting " + name + "\n\n";
        return ret;
    }
};

template<typename Func>
auto makeFuncWrapper(Func func, std::string name) {
    return FuncWrapper<Func>(func, name);
}

int main() {

    auto helloWorld = []() { std::cout << "Hello World\n"; };
    auto addTwoNums = [](int a, int b) { std::cout << "Adding numbers...\n"; return a + b; };

    // makeFuncWrapper(helloWorld, "helloWorld")(); // error: 'void ret' has incomplete type.
    std::cout << makeFuncWrapper(addTwoNums, "addTwoNums")(4, 5) << '\n';

}

This class FuncWrapper works fine and adds an additional functionality to the passed function, until the passed function is a function that returns void. I get an error that the type of ret is incomplete. Is there any other way to make it work even with functions with return type of void? I know that I can't have a void variable, but here, the only purpose of ret is to be returned after the function is done and it's not gonna be used in a wrong way. Is there a solution or some workaround to make it work? Any better way of implementing a function wrapper that wraps any function?

StackExchange123
  • 1,871
  • 9
  • 24
  • 1
    Depend what standard ypu use, you have either create a SFINAE scheme or use `if constrexpr` with "wrappers" around "wrappers", which would service void and non-void result. Also, if you would like to accept other callable , e.g. lsmbdas, you have to serve them separately too. Your wrapper looks like `std::invoke` and its boilerplate code is huge. – Swift - Friday Pie May 14 '20 at 20:02
  • 1
    Note: result of lambda expression is not a function, it's an instance of class-type with `operator()` defined. – Swift - Friday Pie May 14 '20 at 20:09

1 Answers1

0

You might use Raii:

template<typename ...Args>
auto operator()(Args ...args) {
    struct EndScope {
        std::string& name;
        ~EndScope() { std::cout << "Exiting " + name + "\n\n"; }
    } endScope(name);

    std::cout << "Entering " + name + '\n';
    return func(args...);
}

You might go further to handle exception with std::uncaught_exceptions

See raii-way-to-get-errors-that-are-caught-during-destruction

Jarod42
  • 203,559
  • 14
  • 181
  • 302