Stateful function pointer for passing C++ capturing lambdas / std::functions to C style callbacks #include &lt;functional&gt;

template&lt;typename return_type, typename... argument_types&gt;
struct stateful_function_pointer
{
  using function_type         = std::function&lt;return_type(argument_types...)&gt;;
  using function_pointer_type = return_type (*) (argument_types..., void*);

  function_pointer_type callback ()
  {
    return [ ] (argument_types... arguments, void* user_data)
    {
      return (*static_cast&lt;function_type*&gt;(user_data))(arguments...);
    };
  }
  void*                 user_data()
  {
    return static_cast&lt;void*&gt;(&amp;function);
  }

  function_type function;
};

The C style callback must be providing a void* user data as its final parameter (which is a de-facto standard). It may be possible to pass additional user data other than the function state, but I do not see the point as the lambda can already capture user state.
An eccentricity: It is instantiated as e.g. stateful_function_pointer&lt;void, int, char*&gt; instead of stateful_function_pointer&lt;void(int, char*)&gt;.
Example usage as requested (wrapping a HDF5 C function in C++):
class link_access_property_list : public property_list
{
public:
  using function_pointer_type = stateful_function_pointer&lt;herr_t, const char*, const char*, const char*, const char*, unsigned*, hid_t&gt;;
  using callback_type = function_pointer_type::function_type;

  bool set_external_link_callback(const callback_type&amp; callback)
  {
    function_pointer_.function = callback;
    return H5Pset_elink_cb(id_, function_pointer_.callback(), function_pointer_.user_data()) &gt;= 0;
  }

protected:
  function_pointer_type function_pointer_;
};

Then I could:
lapl.set_external_link_callback(
  [CAPTURE_WHATEVER_YOU_WANT] 
  (const char*, const char*, const char*, const char*, unsigned*, hid_t) 
  { 
    USE_WHATEVER_YOU_WANT 
    return herr_t(0);
  });
When you have a C callback you usually pass two things

A pointer to a C function
A void* pointer that is passed to your C function.

The C function must know the type of the original object so it can cast the pointer back to its original type. only after it has been cast back can it be used. And you must cast it back to the exact type it was before you converted to void* or you are in undefined behavior.
So this means the C function must understand the original type.
Since your original type is a templated type (i.e. you don't know the type in general) you can't cast it back (unless you templitize the function so that the function you pass to C has a understanding of the templitized types).
The easy way to do this is to implement a virtual interface. Then you can get a pointer to the base class convert this to a void* then in the C function you can convert back to the base class pointer and call the appropriate virtual interface on this base pointer. Virtual dispatch will then take care of calling the correct implementation.

OK found the reference you were eluding to:
Next time just add it to the question.
From: https://support.hdfgroup.org/HDF5/doc1.8/RM/RM_H5P.html#Property-SetELinkCb
herr_t elink_callback(const char* parent_file_name,
                      const char* parent_group_name,
                      const char* child_file_name,
                      const char* child_object_name,
                      unsigned*   acc_flags,
                      hid_t       fapl_id,
                      void*       op_data)
{
    puts(child_file_name);
    return 0;
}

int main(void) {
    hid_t lapl_id = H5Pcreate(H5P_LINK_ACCESS);
    H5Pset_elink_cb(lapl_id, elink_callback, NULL);
    ...
}

Notice at the top of the document it talks about C functions: https://support.hdfgroup.org/HDF5/doc1.8/RM/RM_H5P.html
This library is robably built by a C compiler so the whole ABI is a C ABI. Thus you can not pass any functions of C++ linkage as a parameter to a callback (The C code does not know how to correctly set up the stack frame to make a correct C++ call). You can only pass functions with C linkage.
Now some compilers use a very similar ABI for C and C++ and you may get lucky passing a function that uses C++ linkage, but that just means you are getting lucky.
Things like exceptions (that's just the first thing I can think of) will not be properly tracked across the stack frame boundries when going into C built stack frame.
As you are getting lucky it is likely that sometime in the future it will just suddenly stop working with no way to diagnose the problem.