C++ removing an std::function from a std::vector<std::function<...>>

Your problem is not constness but that that std::function objects can not be compared for equality at all. Your current approach simply will not work.

The solution is to give some sort of unique 'token' during registration to the caller which can be used to unregister later.


You can use std::function<F>::target to get the held function object directly and compare that.

For example, to erase all of the functions that are T::systemBringUp in systemBringUps, you could do something like:

systemBringUps.erase(std::remove_if(systemBringUps.begin(), systemBringUps.end(), [](const auto& f) {
    auto* target = f.template target<decltype(T::systemBringUp)>();
    return target != nullptr && *target == T::systemBringUp;
}), systemBringUps.end());

You can make a helper function to check if a std::function is holding a value:

template<class F, class T>
bool is_function_holding(const std::function<F>& func, const T& target) {
    static_assert(std::is_assignable<std::function<F>&, const T&>::value, "Function could not possibly hold target");
    auto* current_target = func.template target<typename std::decay<T>::type>();
    return current_target != nullptr && *current_target == target;
}

// Later
systemBringUps.erase(std::remove_if(systemBringUps.begin(), systemBringUps.end(), [](const auto& f) {
    return is_function_holding(f, T::systemBringUp);
}, systemBringUps.end());
systemTearDowns.erase(std::remove_if(systemTearDowns.begin(), systemTearDowns.end(), [](const auto& f) {
    return is_function_holding(f, T::systemTearDown);
}, systemTearDowns.end());
// ...

Tags:

C++

C++11