I'm wrapping a C function in a C++ function. The C function accepts a function pointer (with state). I want to allow a C++ callable. A code sample says a thousand words so...
//======================================================
// All this stuff is defined in C somewhere else
// C string type
typedef struct FooString { const char* str; size_t length; } FooString;
// C function pointer type
// This keeps getting called until it returns something with length == 0
typedef FooString (*CFunctionPointer)(void* state);
// Function being wrapped
void quux(CFunctionPointer fPtr, void* state)
{
FooString str;
while(1)
{
str = fPtr(state);
if(str.length == 0)
break;
else
{
// do something
}
}
}
//======================================================
// Here's what I need help with
template<typename IteratorFunctor>
void quuxWrapper(IteratorFunctor& iterator) const
{
// type that the functor returns, and related types
using TIn = decltype(iterator());
using TNoRef = typename std::remove_reference<TIn>::type;
using TYesRef = typename std::add_lvalue_reference<TNoRef>::type;
using TStored = typename std::conditional<std::is_reference<TIn>::value, std::reference_wrapper<TNoRef>, TIn>::type;
// store this on the stack in this function, and pass a pointer to it into the C library
// the C callback will pass back the pointer, and we can get at all this stuff from within the lambda
struct CallbackContext
{
bool isFirst; // is this the first iteration?
IteratorFunctor& iterator; // reference to the iterator in a place we can get to from inside the C function pointer callback
TStored current; // current value (either an actual value stored on the stack, or a reference wrapper)
};
CFunctionPointer cFunctionPtr = [](void* pContext) -> FooString
{
CallbackContext& context = *((CallbackContext*) pContext);
// on the first iteration, we return the value already fetched (need to do this to support things that
// aren't DefaultConstructable). On subsequent iterations, call the functor again.
if(context.isFirst)
context.isFirst = false;
else
context.current = context.iterator();
// this is needed for supporting both references as reference_wrappers and value types. we take a reference
// which forces reference_wrapper to call its conversion operator and is basically a no-op for value types
// (something like context.current.length would fail for reference_wrapper)
TYesRef current = context.current;
// stop iteration if functor returns anything with length 0
if(current.length() == 0)
return FooString{nullptr, 0};
else
return FooString{current.data(), current.length()};
};
// create the context and make the first call to the iterator
CallbackContext context{true, iterator, iterator()};
// and then call the C function
quux(cFunctionPtr, &context);
}
This supports returning a std::string or std::string& from the functor. It also allows users to return their own type, as long as that type has length() and data() methods. It doesn't allow the functor to return a std::string*, though, which is what I'd like to support.
Is there a good way to do this using C++11 features (and no dependencies or weird compiler hacks, since this is part of the public API)?
template<class F, class R=std::result_of_t<F&()>>
struct c_callback {
F state;
void* get_pvoid() { return std::addressof(state); }
using C_sig = R(*)(void*);
static C_sig get_pfunc() {
return [](void* pvoid)->R {
F* pstate = static_cast<F*>(pvoid);
return static_cast<R>( (*state)() );
};
}
};
this wraps a lambda or other C++ invokable into a function pointer and pvoid. It does nothing else. The return value is either deduced or passed.
Your second problem is wanting to adapt return values.
template<class T>
FooString to_foostring_f( T& t ) {
return {t.data(), t.length()};
}
template<class T>
FooString to_foostring_f( T* t ) {
if (!t) return {0,0};
return to_foostring_f(*t);
}
auto to_foostring = [](auto&& t)->FooString {
return to_foostring_f( decltype(t)(t) );
};
to_foostring is a function object that takes something, and returns a FooString. It does this by calling to_foostring_f. You can enhance it with ADL.
Finally write compose(First, Second) which returns Second(First(Args...)).
Stitch these together and it should work.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have built a templated functor object which I can use to manage lambdas which need to recurse and survive across scopes. It's not very pretty (it uses void pointers and an std::function instance), but it works for the use-cases I need it to. (I'd appreciate if posters could withhold comments about how it's not type-safe and terribly bad practice. I'm aware.)
There is a glaring issue with it, however: it can't handle lambdas which return void, because some of the paths try to store return values in a variable. I need to know how to use if constexpr statements to detect if the result of the functor's lambda is void, and handle it appropriately. This isn't a unique problem, but all the results I've found are extremely out of date, many of them using the now-depreciated result_of_t.
Any help would be greatly appreciated.
#include <iostream>
#include <string>
#include <functional>
#define uint unsigned int
//! A standardised wrapper for lambda functions, which can be stored in pointers, used recursively, keep track of external storage via a void *, and set to self destruct when no longer useful.
template <class F, bool UsesDataStorage>
class Functor {
protected:
std::function<F> m_f; //!< The lambda stored by the wrapper
void* m_data = nullptr; //!< A void pointer which will be given to the lambda if `UsesDataStorage`. Note that cleanup is delegated to the lambda; the functor instance will not handle it.
bool m_selfDestructing = true; //!< Whether the combinator will self-destruct should its lambda mark itself as no longer useful.
bool m_selfDestructTrigger = false; //!< Whether the combinator's lambda has marked itself as no longer useful.
public:
inline bool usesDataStorage() const { return UsesDataStorage; } //!< Return whether this functor is set up to give its function a `data` void-pointer, which will presumably be set to a data-structure.
inline void* getData() const { return m_data; } //!< Returns the void pointer which is passed to the lambda at each call (if the functor instance uses data storage).
inline void setData(void* data) { m_data = data; } //!< Sets the void pointer which is passed to the lambda at each call (if the functor instance uses data storage).
inline bool canSelfDestruct() const { return m_selfDestructing; } //!< Returns whether the LambdaWrapper will delete itself when instructed to by the contained lambda.
inline void triggerSelfDestruct() { m_selfDestructTrigger = true; } //!< Triggers wrapper self-deletion at the end of ruinning the lambda.
Functor(const std::function<F>& f, bool canSelfDestruct = true) :
m_f(f),
m_selfDestructing(canSelfDestruct)
{} //!< Constructor for Functor instances which DON'T use data storage. Note that the given function should always take a void pointer as the first argument, which is where a pointer to the Functor instance will be passed.
Functor(std::function<F>&& f, bool canSelfDestruct = true) :
m_f(f),
m_selfDestructing(canSelfDestruct)
{} //!< Constructor for Functor instances which DON'T use data storage. Note that the given function should always take a void pointer as the first argument, which is where a pointer to the Functor instance will be passed.
Functor(const std::function<F>& f, void* data, bool canSelfDestruct = true) :
m_f(f),
m_data(data),
m_selfDestructing(canSelfDestruct)
{} //!< Constructor for Functor instances which DO use data storage. Note that the given function should always take a void pointer as the first argument, which is where a pointer to the Functor instance will be passed, and a void * for the second argument, which is where the data storage pointer is passed.
Functor(std::function<F>&& f, void* data, bool canSelfDestruct = true) :
m_f(f),
m_data(data),
m_selfDestructing(canSelfDestruct)
{} //!< Constructor for Functor instances which DO use data storage. Note that the given function should always take a void pointer as the first argument, which is where a pointer to the Functor instance will be passed, which is where the data storage pointer is passed.
template <typename... Args>
decltype(auto) operator()(Args&&... args) {
// Avoid storing return if we can,
if (!m_selfDestructing) {
if constexpr (UsesDataStorage) {
// Pass itself to m_f, then the data storage, then the arguments.
// This should work even if the return type is void, as far as I can tell.
return m_f(this, m_data, std::forward<Args>(args)...);
}
else {
// Pass itself to m_f, then the arguments.
// This should work even if the return type is void, as far as I can tell.
return m_f(this, std::forward<Args>(args)...);
}
}
else {
if constexpr (UsesDataStorage) {
// Pass itself to m_f, then the data storage, then the arguments.
// ----- !!! -----
// The following if constexpr statement is what I can't work out how to do.
// ----- !!! -----
if constexpr (std::is_same<std::invoke_result_t<std::function<F>>, void>) {
m_f(this, m_data, std::forward<Args>(args)...);
// self-destruct if necessary, allowing lamdas to delete themselves if they know they're no longer useful.
if (m_selfDestructTrigger) { delete this; }
return;
}
else {
auto r = m_f(this, m_data, std::forward<Args>(args)...);
// self-destruct if necessary, allowing lamdas to delete themselves if they know they're no longer useful.
if (m_selfDestructTrigger) { delete this; }
return r;
}
}
else {
// Pass itself to m_f, then the arguments.
// ----- !!! -----
// The following if constexpr statement is what I can't work out how to do.
// ----- !!! -----
if constexpr (std::is_same<std::invoke_result_t<std::function<F>>, void>) {
m_f(this, std::forward<Args>(args)...);
// self-destruct if necessary, allowing lamdas to delete themselves if they know they're no longer useful.
if (m_selfDestructTrigger) { delete this; }
return;
}
else {
auto r = m_f(this, std::forward<Args>(args)...);
// self-destruct if necessary, allowing lamdas to delete themselves if they know they're no longer useful.
if (m_selfDestructTrigger) { delete this; }
return r;
}
}
}
}
};
template <class F> Functor(std::function<F>, bool)->Functor<F, false>;
template <class F> Functor(std::function<F>, void*, bool)->Functor<F, true>;
int main() {
Functor f1 = Functor(std::function([](void* self, uint val1) -> uint {
std::cout << "f1(" << val1 << ") was called." << std::endl;
return 2u * val1;
}), false);
Functor f2 = Functor(std::function([](void* self, uint val1) -> void {
std::cout << "f2(" << val1 << ") was called." << std::endl;
return;
}), false);
auto x = f1(3u); // Compiles and works.
f2(3u); // Doesn't compile.
}
The line I'm looking for is this:
if constexpr (std::is_same<std::function<F>::result_type, void>::value) {}
Many thanks to #NathanOliver!
Normally when a pointer to an object is created and returned from a function you consume it using unique_ptr to ensure it is deleted at the end of the scope.
CustomType* GetTheObject(); // Let's say this the function signature and it returns a new object
void Main() {
auto object = make_unique(GetTheObject());
object->DoSomething();
// Then the object is deleted automatically
}
What if the function signature is like this
bool GetTheObject(CustomType** object);
I can imagine a rather verbose way to consume it
void Main() {
// Declare a pointer which we never need
CustomType* object_ptr;
if(GetTheObject(&object_ptr)) {
// Then create a unique_ptr out of it
auto object = make_unique(object_ptr);
object->DoSomething();
// Then the object is deleted automatically
}
}
Is there a better recommended way how to consume an object in this case. I can think about another let's say unique_ptr2 class which implements & operator and then use it like
unique_ptr2 object;
if(GetTheObject(&object)) {
// use it
}
Is there a ready to be used implementation of unique_ptr2 which would allow doing that? It still feel to be not ideal. Is there a better way?
I might be tempted to write code that automates the conversion to/from the unique ptr. We generate a new function from our existing function "automatically" that has the same signature, but T* return values are unique_ptr<T> and T** arguments are unique_ptr<T>* arguments.
Then we inject the conversion boilerplate using RAII and template metaprogramming.
A ptr_filler is a RAII type that converts a unique_ptr<T>* into a T**:
template<class T>
struct ptr_filler {
std::unique_ptr<T>* output = nullptr;
T* temporary = nullptr;
ptr_filler( std::unique_ptr<T>* bind ):output(bind) {}
operator T**()&&{return &temporary;}
~ptr_filler() {
if (temporary)
*output = std::unique_ptr<T>(temporary);
}
};
ret_converter_t does a type conversion from the C-style API to a C++ unique-ptr API:
template<class T> struct ret_converter { using type=T; };
template<class T> using ret_converter_t = typename ret_converter<T>::type;
template<class T> struct ret_converter<T*> { using type=std::unique_ptr<T>; };
get_converter_t converts argument types from the C-style API, to one that fills unique ptrs via a ptr_filler:
template<class T> struct get_converter { using type=T; };
template<class T> using get_converter_t = typename get_converter<T>::type;
template<class T> struct get_converter<T**> { using type=ptr_filler<T>; };
Finally, call deduces its arguments from the function pointer you pass it, then converts the arguments and retval to use unique ptr memory management, and calls the function f for you:
template<class R, class...Args>
ret_converter_t<R> call( R(* f)(Args...), get_converter_t<Args>... args ) {
return static_cast<ret_converter_t<R>>( f( std::forward<decltype(args)>(args)... ) );
}
now we can:
struct CustomType {
int x;
};
CustomType* GetTheObject(int x) { return new CustomType{x}; }
bool MakeTheObject( CustomType** pp, int a, int b ) { *pp = new CustomType{a+b}; return a>b; }
we can do:
int main() {
std::unique_ptr<CustomType> ptr;
std::cout << call( MakeTheObject, &ptr, 2, 1 ) << " = 1\n";
std::cout << ptr->x << " = 3\n";
ptr = call( GetTheObject, 7 );
std::cout << ptr->x << " = 7\n";
}
You can get fancier with call<MakeTheObject> syntax, but it takes work. This assumes that the API you are wrapping is an C-ish API but returns new'd objects.
Live example.
I would think that returning a std::unique_ptr would be safer than returning a raw pointer, since returning a raw pointer risks the calling code accidentally leaking the object. I'd recommend doing it this way:
#include <iostream>
#include <memory>
class CustomType
{
// ...
};
std::unique_ptr<CustomType> GetTheObject()
{
if ((rand()%2) != 0) return std::make_unique<CustomType>();
return std::unique_ptr<CustomType>(); // nothing to return, sorry
}
int main(int argc, char ** argv)
{
if (std::unique_ptr<CustomType> p = GetTheObject())
{
std::cout << "Got the object!" << std::endl;
}
return 0;
}
If you have to live with an existing function that you don't like the shape of and can't change, you can hide the ugliness inside a wrapper function and then call the wrapper function instead:
std::unique_ptr<CustomType> PrettyGetTheObject()
{
CustomObject * obj;
if (GetTheObject(&obj)) return std::unique_ptr<CustomObject>(obj);
return std::unique_ptr<CustomType>(); // nothing to return, sorry
}
A possible approach is to use a wrapper function. Example:
bool GetOriginal(char **pptr);
bool GetWrapped(std::unique_ptr<char> * puptr) {
bool result;
if (puptr != nullptr) {
char * cptr;
result = GetOriginal(&cptr);
*puptr = std::make_unique(cptr);
} else {
result = GetOriginal(nullptr);
}
return result;
}
This assumes the commonly used pattern of passing null to avoid getting a pointer to manage (e.g. if you're only interested in the return value).
If passing null to the original function is not part of its api, then you could of course use a reference to a std::unique_ptr instead of a raw pointer.
If you have many such functions you could also write a general wrapper function for that, of course:
template<typename Fn, typename T>
bool wrap(Fn fn, std::unique_ptr<T> * puptr) {
bool result;
if (puptr != nullptr) {
T * cptr = nullptr;
result = fn(&cptr);
*puptr = std::make_unique(cptr);
} else {
result = fn(nullptr);
}
return result;
}
// usage: wrap(GetOriginal, &some_unique_ptr)
If the original function takes more arguments, then use std::bind or a lambda.
Let's suppose I have the following function interface:
void giveme(void (*p)());
That function simply accepts a pointer to a function with no return type and argument.
I'm wondering if exists a way (without change the interface) to pass a class method as parameter of that function.
I'll try to explain better with an example. I have a class, like:
class Foo {
public:
template<typename T>
void bar();
};
I want to pass bar<T> (of an addressable instance of the class) as parameter of the function giveme.
I thought to bind the method with an object, and obtain the function target.
Something like:
int main(int argc, char *argv[]) {
Foo foo;
std::function<void()> f = std::bind(&Foo::bar<int>, &foo);
giveme(f.target<void()>());
return 0;
}
It compiles, but obviously does not work because, from here:
TargetType shall match the target type, so that typeid(TargetType)==target_type(). Otherwise, the function always returns a null pointer.
So, if exists, what is a way to achieve it?
Here's one (very bad) idea:
Foo * foo_ptr; // maybe thread_local
void foo_call()
{
foo_ptr->bar<int>();
}
int main()
{
Foo foo;
foo_ptr = &foo;
give_me(&foo_call);
}
It's not pretty, but neither is your situation.
There's only one way I know of, and it's a terrible idea, and don't do this.
typedef void (*void_fn)();
struct stateful_void_fn_data = {
void_fn raw;
std::function<void()> actual;
std::atomic_bool in_use;
}
// a global array to hold your function bindings and such
extern stateful_void_fn_data stateful_functions[5];
// N stateless functions that defer to the correct global state
template<int n> void void_fn_impl() {stateful_functions[n].actual();}
extern stateful_void_fn_data stateful_functions[5] =
{{void_fn_impl<0>}, {void_fn_impl<1>}, {void_fn_impl<2>}, {void_fn_impl<3>}, {void_fn_impl<4>}};
// function to register a stateful and get a stateless back
void_fn allocate_void_fn(std::function<void()>&& f) {
for(int i=0; i<5; i++) {
if(stateful_functions[i].in_use.compare_exchange_weak(false, true)) {
stateful_functions[i].actual = std::move(f);
return stateful_functions[i].raw;
}
}
throw std::runtime_error("ran out of stateful functions :(");
}
// function to unregister
void free_void_fn(void_fn f) {
if (f == nullptr) return;
for(int i=0; i<5; i++) {
if (stateful_functions[i].raw == f) {
stateful_functions[i].in_use = false;
return;
}
}
throw std::runtime_error("unknown void function");
}
Basically, I generate 5 void() functions (void_fn_impl<N>), and each calls a function stored in one of the five a global array slots (stateful_functions[i].actual). Then, allocate_void_fn will store any std::function<void()> in the global array, and hand you the void() that calls that entry in the array. This function itself is stateless, because we've stored all the state in the global array. free_void_fn and in_use exist solely to make the functions reusable.
And of course, because RAII is good:
class hidden_state_void_fn {
void_fn raw;
public:
hidden_state_void_fn(std::function<void()>&& f)
:raw(allocate_void_fn(std::move(f)) {}
hidden_state_void_fn(const hidden_state_void_fn&& r) {
raw = r.raw;
r.raw = nullptr;
}
hidden_state_void_fn& operator=(const hidden_state_void_fn&& r) {
free_void_fn(raw);
raw = r.raw;
r.raw = nullptr;
}
~hidden_state_void_fn() {free_void_fn(raw);}
operator void_fn() {return raw;}
operator()() {raw();}
};
std::map<int,std::function<void()>> tasks;
template<int n>
struct task_wrapper{
static void f(){ if (tasks.count(n)) tasks[n](); }
task_wrapper(std::function<void()> fin){ tasks[n]=fin; }
~task_wrapper(){ tasks.erase(n); }
static std::shared_ptr< void(*)() > make(std::function<void()> fin){
auto self=std::make_shared<task_wrapper>(fin);
return { &f, fin };
}
};
A task_wrapper<N>::make(func) return a shared pointer to a stateless function pointer that will call the stateful func.
We can use the the usual techniques to create an array of K function pointers of signature shared_ptr<void(*)()>(*)(). Then we can have a shared_ptr<void(*)()> register_func( std::function<void()> ).
To find blanks, we can either do a linear search, or we could build a table of blanks. This could look like a traditional allocation/free "heap", or a range-tree of blanks, or whatever.
Another approach would be to literally create and save a DLL on the fly then load it and call the symbol. This could be done via hacks (have such a DLL and a known offset to modify, copy and write, then load and run) or by shipping a C++ compiler (or other compiler) with your code (!).
I would like to be able to write a template function that can invoke a function call on all elements of a container. We can assume that the function name is always the same. However what isn't known is whether the container is holding objects or pointers. ie, whether I should de-reference.
template< typename TContainer >
void ProcessKeyedContainer( TContainer &keyedContainer )
{
for ( auto it = keyedContainer.begin(); it != keyedContainer.end(); ++it )
{
// do some random stuff here.
// ...
auto value = it->second;
value.Process(); // or value->Process() if the container has pointers
}
}
...
std::map< int, CMyObject > containerOfObjects;
containerOfObjects[0] = CMyObject();
std::map< int, CMyObject* > containerOfPointers;
containerOfPointers[0] = new CMyObject();
// I would like both calls to look near identical
ProcessKeyedContainer( containerOfObjects );
ProcessKeyedContainer( containerOfPointers );
Is there a neat way to be able to make the Process call inside ProcessKeyedContainer, without putting a burden on the caller ( ie the caller doesn't have to know to use it in one way for pointers and another way for objects ), and without having to duplicate too much code ?
Overloaded function template is the savior:
template<typename T>
void invoke(T * obj) //when object is pointer
{
obj->Process();
}
template<typename T>
void invoke(T & obj) //when object is non-pointer
{
obj.Process();
}
then use it as:
auto value = it->second;
invoke(value); //correct invoke() will be selected by the compiler!
But that is not good enough, as you might want to do something else also with value in the rest of the function written by you. So if you follow the above approach, there will be code duplication, as both invoke() will have almost similar code.
So here is one improvement: instead of using invoke(), turn the pointer into reference so that you could use it uniformly in your function.
template<typename T>
T& ensure_ref(T * obj) //when object is pointer
{
return *obj; //return the dereferenced object
}
template<typename T>
T& ensure_ref(T & obj) //when object is non-pointer
{
return obj; //simply return it
}
And use it as:
auto & value = ensure_ref(it->second); //call ensure_ref to ensure reference!
value.Process(); //value is gauranteed to be NOT pointer!
//you might want to do this also!
value.xyz = abc;
Hope that helps!
how to remove function that bound to member function of this object :
std::vector<std::function<void(int)>> callbacks;
class MyClass {
public:
MyClass() {
callbacks.push_back(
std::bind(&MyClass::myFunc,this,std::placeholders::_1)
);
}
~MyClass() {
auto it = std::remove_if( std::begin(callbacks),
std::end(callbacks),
[&](std::function<void(int)>& f) {
return // <-- this is my question
// true (remove) if f is bound to member function
// of this
});
callbacks.erase(it,std::end(callbacks));
}
void myFunc(int param){...}
};
typedef decltype(std::bind(&MyClass::myFunc,this,std::placeholders::_1)) bound_type;
auto it = std::remove_if( std::begin(callbacks),
std::end(callbacks),
[](const std::function<void(int)>& f) {
return f.target<bound_type>() != nullptr;
});
The member function template std::function::target<T> returns a pointer to the target object if it is of type T, otherwise it returns null. So you just need to be able to name the type of the target object, which you can get from decltype. Pretty simple really :-)
N.B. that will remove any callbacks of that type, not only ones that have bound the this pointer for the specific object being destroyed. If you are trying to prevent invoking callbacks on an object after it has been destroyed and have no possible way to identify which elements of the vector refer to which objects, you could consider putting a shared_ptr in your class, then storing a weak_ptr to it in the callback, which can be used to detect if the object has been destroyed:
class MyClass
{
struct NullDeleter { void operator()(void*) const { } };
std::shared_ptr<MyClass> sp;
static void safe_invoke(void (MyClass::*f)(int), const std::weak_ptr<MyClass>& wp, int i)
{
if (std::shared_ptr<MyClass> safe_this = wp.lock())
(safe_this.get()->*f)(i);
}
public:
MyClass() : sp(this, NullDeleter()) {
callbacks.push_back(
std::bind(safe_invoke, &MyClass::myFunc ,std::weak_ptr<MyClass>(sp),
std::placeholders::_1)
);
};
This wraps the call to the member function with the invoke function that converts the weak_ptr to a shared_ptr before calling the member function. If the object has been destroyed the shared_ptr will be empty, so the function does nothing. This doesn't actually remove the callback when it becomes invalid, but does make it safe to call.
You can't in the general case without a buttload of extra work. Type erasure clears this information from the object, and std::function does not expose this information directly.
Your specific example may only have one member function that could be the candidate to remove, but what about a class with 5 members that could be stored as callbacks? You'll need to test for all of them, and it's also possible to bind member functions using a lambda, which is pretty much undetectable.
Here's one solution if:
all callbacks are registered from within MyClass
the container is amended to store extra information
you're willing to do all the extra bookkeeping
std::vector<std::pair<std::function<void(int)>, void*>> callbacks;
class MyClass{
static unsigned const num_possible_callbacks = 2; // keep updated
std::array<std::type_info const*, num_possible_callbacks> _infos;
unsigned _next_info;
// adds type_info and passes through
template<class T>
T const& add_info(T const& bound){
if(_next_info == num_possible_callbacks)
throw "oh shi...!"; // something went out of sync
_infos[_next_info++] = &typeid(T);
return bound;
}
public:
MyClass() : _next_info(0){
using std::placeholders::_1;
callbacks.push_back(std::make_pair(
add_info(std::bind(&MyClass::myFunc, this, _1)),
(void*)this));
callbacks.push_back(std::make_pair(
add_info([this](int i){ return myOtherFunc(i, 0.5); }),
(void*)this));
}
~MyClass(){
using std::placeholders::_1;
callbacks.erase(std::remove_if(callbacks.begin(), callbacks.end(),
[&](std::pair<std::function<void(int)>, void*> const& p) -> bool{
if(p.second != (void*)this)
return false;
auto const& f = p.first;
for(unsigned i = 0; i < _infos.size(); ++i)
if(_infos[i] == &f.target_type())
return true;
return false;
}), callbacks.end());
}
void myFunc(int param){ /* ... */ }
void myOtherFunc(int param1, double param2){ /* ... */ }
};
Live example on Ideone.
I once needed to do something like this and I solved it by storing a vector of shared pointers of objects in the class that contain the function and remove the function from the vector by value when they are destroyed, which also makes this automatic.