15

I'm trying to create a generic wrapper function that takes a function as a template argument and takes the same arguments as that function as its arguments. For example:

template <typename F, F func>
/* return type of F */ wrapper(Ts... Args /* not sure how to get Ts*/)
{
    // do stuff
    auto ret = F(std::forward<Ts>(args)...);
    // do some other stuff
    return ret;
}

The solution needs to be castable to a function pointer with the same type as func so that I can pass it to a C api. In other words, the solution needs to be a function and not a function object. Most importantly, I need to be able to do work in the wrapper function.

If the inline comments aren't clear, I'd like to be able to do something like the following:

struct c_api_interface {
    int (*func_a)(int, int);
    int (*func_b)(char, char, char);
};

int foo(int a, int b)
{
    return a + b;
}

int bar(char a, char b, char c)
{
    return a + b * c;
}

c_api_interface my_interface;
my_interface.func_a = wrapper<foo>;
my_interface.func_b = wrapper<bar>;

I looked for related posts and found these, but none of them are quite what I'm trying to do. Most of these posts concern function objects. Is what I'm trying to do even possible?

Function passed as template argument

Function wrapper via (function object) class (variadic) template

How does wrapping a function pointer and function object work in generic code?

How do I get the argument types of a function pointer in a variadic template class?

Generic functor for functions with any argument list

C++ Functors - and their uses

In response to the first 2 responses, I edited the question to make it clear that I need to be able to do work in the wrapper function (i.e. modify some global state before and after the call to the wrapped function)

Community
  • 1
  • 1
Eric
  • 165
  • 1
  • 1
  • 6

7 Answers7

11
template<class F, F f> struct wrapper_impl;
template<class R, class... Args, R(*f)(Args...)>
struct wrapper_impl<R(*)(Args...), f> {
    static R wrap(Args... args) {
        // stuff
        return f(args...);
    }
};

template<class F, F f>
constexpr auto wrapper = wrapper_impl<F, f>::wrap;

Use as wrapper<decltype(&foo), foo>.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Thank you so much, this worked perfectly! :) For others: the variable template is a c++14 feature I believe, so that may not work on all compilers. I defined a macro `#define wrapper(func) wrapper_impl::wrap` that accomplishes roughly the same thing. – Eric Apr 08 '16 at 06:44
  • Could this be adapted to accomodate optional arguments? Meaning that args optional in the wrapped function are optional in the wrapper as well. In this variant, all arguments have to be specified. – eudoxos Jan 10 '18 at 10:06
  • do you think it is possible to extend to wrap a member function? I have tried to add a typename T in template and a T *t as template parameter too. Then calling the function by t->f(args...) but it simply doesn't work – milanow Aug 21 '19 at 23:30
  • This errors out in C++17 with: " error: implicit instantiation of undefined template" – A. K. Mar 05 '20 at 00:22
9
#include <utility>
#include <iostream>

struct c_api_interface { int (*func_a)(int, int); int (*func_b)(char, char, char); };
int foo(int a, int b) { return a + b; }
int bar(char a, char b, char c) { return a + b * c; }


template<typename Fn, Fn fn, typename... Args>
typename std::result_of<Fn(Args...)>::type
wrapper(Args... args) {
   std::cout << "and ....it's a wrap ";
   return fn(std::forward<Args>(args)...);
}
#define WRAPIT(FUNC) wrapper<decltype(&FUNC), &FUNC>

int main() {
  c_api_interface my_interface;
  my_interface.func_a = WRAPIT(foo);
  my_interface.func_b = WRAPIT(bar);

  std:: cout << my_interface.func_a(1,1) << std::endl;
  std:: cout << my_interface.func_b('a','b', 1) << std::endl;

  return 0;
}

see http://rextester.com/ZZD18334

VolkerK
  • 95,432
  • 20
  • 163
  • 226
  • Thank you! I'm changing this to the accepted answer because it's shorter that of @T.C., uses just a function and not a struct, uses `std::forward`, and (as a matter of opinion) is easier to understand because you did not use template argument specialization. – Eric Apr 08 '16 at 06:55
  • Though I have to admit the std::forward is only in there because I tried something that would compile under MSVC and then thought "ah screw it, not gonna happen ...but hey, keep the forward" ;-) – VolkerK Apr 08 '16 at 07:27
  • 1
    What is the proper way to declare an alias for the wrapper which will look like a normal function to call? Something like `using a_wrapped=wrapper;` (but this one does not work). – eudoxos Jan 10 '18 at 09:26
  • 2
    This approach will not work through the `WRAPIT` macro if a function is overloaded. – Kentzo Mar 03 '18 at 01:30
  • It also doesn't seem to work for classes that you call via `operator()`. By the way in C++17 you should use `std::invoke_type_t<>` insead of `std::result_of<>::type`. – Timmmm Sep 27 '21 at 14:35
1

you may try something like that (Ugly, but works)

#include <iostream>
#include <functional>

struct wrapper_ctx
{
  wrapper_ctx ()
  {
    std::cout << "Before" << std::endl;
  }
  ~wrapper_ctx ()
  {
    std::cout << "after" << std::endl;
  }
};

template <typename F, typename... Args>
auto executor (F&& f, Args&&... args) -> typename std::result_of<F(Args...)>::type
{
  wrapper_ctx ctx;
  return std::forward<F>(f)( std::forward<Args>(args)...);

}

template <typename F>
class wrapper_helper;


template<typename Ret, typename... Args>
class wrapper_helper <std::function<Ret(Args...)>>
{
  std::function<Ret(Args...)> m_f;
public:
  wrapper_helper( std::function<Ret(Args...)> f ) 
      : m_f(f) {}
  Ret operator()(Args... args) const 
  { 
    return executor (m_f, args...); 
  }
};

template <typename T>
wrapper_helper<T> wrapper (T f)
{
  return wrapper_helper <T>(f);
}


int sum(int x, int y)
{
  return x + y;
}


int main (int argc, char* argv [])
{

  std::function<int(int, int)> f = sum;
  auto w = wrapper (f);

  std::cout << "Executing the wrapper" << std::endl;
  int z = w(3, 4);

  std::cout << "z = " << z << std::endl;
}
0

you probably need something like

template <typename F>
class Wrapper {
public:
    Wrapper(F *func) : function(func) {}
    operator F* () { return function; }
    F *function;
};

Which you can use like void (*funcPtr)(int) = Wrapper<void(int)>(&someFunction);

Andrei R.
  • 2,374
  • 1
  • 13
  • 27
  • I appreciate the response, but this doesn't do what I asked for in the original post. In your solution, if I call `funcPtr()` it calls `someFunction`. I would like it to call a function that does some work before and after calling `someFunction`. – Eric Apr 08 '16 at 05:40
  • 1
    @Eric, now I understand what you want and don't understand why are you looking for such a hard way. Lambda functions without capturing are castable to c function pointers: `void (*funcPtr)(int) = [](int a){ /*smth*/};` - call wrapped function and before/after routines right inside lambda – Andrei R. Apr 08 '16 at 06:26
  • I tried that at first. I believe lambdas are only castable to function pointers if they don't capture, and to make this generic I needed to write a lambda that captures the function it's going to call, but maybe there's a way to make that work that I'm missing. – Eric Apr 08 '16 at 06:47
0

I think that will be the concise way to do what you want:

template <typename F>
F* wrapper(F* pFunc)
{
    return pFunc;
}

and use it like this:

my_interface.func_a = wrapper(foo);
my_interface.func_a(1, 3);
Alexey Andronov
  • 582
  • 6
  • 28
  • Thanks for the response, but this doesn't do what I asked for. I need to be able to do some work in the wrapper function before and after I call the wrapped function (in this case `foo`). Thus the wrapper function needs to have the **same function signature as the wrapped function**. – Eric Apr 08 '16 at 05:50
  • I'm not sure you can retrieve signature from template arguments (namely `Ts... Args`) but you can save them for deferred call as showed [here](http://stackoverflow.com/questions/15537817/c-how-to-store-a-parameter-pack-as-a-variable) and then in `Wrapper::operator()` do stuff before and after call to underlying func with saved arguments – Alexey Andronov Apr 08 '16 at 06:32
0

You may try this

template <class R, class... Args>
struct wrap
{
    using funct_type = R(*)(Args...);
    funct_type func;
    wrap(funct_type f): func(f) {};
    R operator()(Args&&... args)
    {
          //before code block
          std::cout << "before calling\n";
          R ret=func(std::forward<Args>(args)...);
          //after code block
          std::cout << "After calling\n";
    }
};

use like this for example:

int somefunc(double &f, int x);
auto wrapped_somefunc=wrap{somefunc};
double f=1.0;
int x = 2;
auto result=wrapped_somefunc(f,x);
  • No perfect forwarding? – Osyotr Nov 27 '22 at 15:36
  • You pass function pointers as parameter there's no need i think for perfect forwarding – Oscar Kuchuk Nov 28 '22 at 11:16
  • I mean here: `R operator()(Args... args)`. Could have been `R operator()(Args&&... args)` and later `R ret=func(std::forward(args)...);` – Osyotr Nov 28 '22 at 12:55
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 30 '22 at 09:35
0

This one is for c++17 and newer uses auto template parameters:

template <auto func, class... Args>
auto wrap_func(Args... args)
{
    std::cout << "before calling wrapped func\n";
    auto ret = func(args...);
    std::cout << "after calling wrapped func\n";
    return ret;
}

use for example:

int some_func(int a, int b);
auto ret = wrap_func<some_func>(2, 3);