How to remove a std::function<void()> in vector? - c++

I'm trying to create C# event in c++ for my game engine. I'm implementing the event system now but I don't know how to remove a std::function in a vector. Am I using the correct list?
I'm quite new in C++ but I'm a C# programmer for 10 years now. Is this possible in C++?
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
struct Delegate {
std::vector<std::function<void()>> funcs;
template<class T> void operator+=(T mFunc)
{
funcs.push_back(mFunc);
}
template<class T> void operator-=(T mFunc)
{
// How?
//funcs.erase(std::remove(funcs.begin(), funcs.end(), mFunc), funcs.end());
}
void operator()() {
for (auto& f : funcs) f();
}
};
void fun1()
{
std::cout << "hello, ";
}
void fun2()
{
std::cout << "Delete";
}
void fun3()
{
std::cout << "world!" << std::endl;
}
int main() {
Delegate delegate;
delegate += fun1;
delegate += fun2;
delegate -= fun2;
delegate += fun3;
delegate();
}

If you are willing to limit Delegate to only using function pointers the you can do it with what you have. That would look like
struct Delegate {
std::vector<void(*)()> funcs;
template<class T> void operator+=(T mFunc)
{
funcs.push_back(mFunc);
}
template<class T> void operator-=(T mFunc)
{
funcs.erase(std::remove(funcs.begin(), funcs.end(), mFunc), funcs.end());
}
void operator()() {
for (auto& f : funcs) f();
}
};
If you don't want to do so, then you need to change you approach. You could have operator += return an index to the inserted function, and then you can change operator -= to take that index and remove that element. see eerorika's answer for a suggestion on how to return iterators to the functions.

Is this possible in C++?
Not like this. Function wrappers cannot be compared for equality. This is a limitation in their design.
One option is to use function pointers. They can be compared for equality. But then you cannot use stateful function objects. NathanOliver shows an example of this.
Another alternative design would be to use a std::list as the container, and when ever you register a function, return iterator to it. Then, instead of erasing by passing the function, you can pass the iterator to be erased.

std::function objects are not directly comparable, but if you are only using regular functions (not e.g. member functions or capturing lambdas), you can use target() method to extract underlying pointer.
void operator-=(void(*mFunc)())
{
auto pred = [&mFunc](const std::function<void()>& func) { return mFunc == *func.target<decltype(mFunc)>(); };
funcs.erase(std::remove_if(funcs.begin(), funcs.end(), pred), funcs.end());
}
I changed the type T to be function pointer explicitly, because std::function would need a different approach (calling target() on that too). You can overload your operator -= to handle std::function separately.
It's ugly, but it works.
Note: Above snippet doesn't really take into account type safety. target() will return nullptr if type declared by template does not match the actual type stored by std::function, and dereferencing nullptr will be disastrous. Since your code only seems to deal with free functions of signature void(), it shouldn't be much issue, but if you plan to use lambdas or something it may break.

Related

How to use a compile-time interface with a runtime type?

I have a function that takes a T and calls specific functions on the supplied object. Until now it was used from compile-time objects, so all was great. Minimal example:
#include <iostream>
struct A {
void fun() const { std::cout << "A" << std::endl; }
};
struct B {
void fun() const { std::cout << "B" << std::endl; }
};
template<class T>
void use_function(const T& param) {
param.fun();
}
int main() {
use_function(A{}); // "A"
use_function(B{}); // "B"
return 0;
}
Now I'm trying to use that use_function() with objects that get created at runtime and having a hard time. I can't use std::variant or std::any since I need to supply the type as template parameter for their access functions - although all their variants fulfil the function interface. Example for a (failing) variant approach:
using var_type = std::variant<A, B>;
struct IdentityVisitor {
template<class T>
auto operator()(const T& alternative) const -> T {
return alternative;
}
};
int main() {
var_type var = A{};
// error C2338: visit() requires the result of all potential invocations to have the same type and value category (N4828 [variant.visit]/2).
use_function(std::visit(IdentityVisitor{}, var));
return 0;
}
What is possible is directly calling the function with an appropriate type like this:
if (rand() % 2 == 0)
use_function(A{});
else
use_function(B{});
just storing it in between is what I can't get working.
I understand on a technical level but having trouble coming up with an elegant solution. Is there one? I know that I could rewrite the objects with even a lightweight inheritance - but was trying to see if it's feasible to avoid it altogether, even if just as an exercise to avoid OOP in favor of templates and concepts. I feel like variants should be working with this, but apparently not.
std::visit([](auto const& x) { use_function(x); }, var);
If overload sets were objects, you could pass use_function to std::visit directly. Because they aren't, you need to wrap it in something that will be instantiated as a call to the right overload.
std::visit([](auto const& x) { use_function(x); }, var);

Passing a lambda with moved capture to function

I recently struggled with a bug hard to find for me. I tried to pass a lambda to a function taking a std::function object. The lambda was capturing a noncopyable object.
I figured out, obviously some copy must happen in between all the passings. I came to this result because I always ended in an error: use of deleted function error.
Here is the code which produces this error:
void call_func(std::function<void()> func)
{
func();
}
int main()
{
std::fstream fs{"test.txt", std::fstream::out};
auto lam = [fs = std::move(fs)] { const_cast<std::fstream&>(fs).close(); };
call_func(lam);
return 0;
}
I solved this by capseling the std::fstream object in an std::shared_ptr object. This is working fine, but I think there may be a more sexy way to do this.
I have two questions now:
Why is this error raising up?
My idea: I generate many fstream objects and lambdas in a for loop, and for each fstream there is one lambda writing to it. So the access to the fstream objects is only done by the lambdas. I want do this for some callback logic. Is there a more pretty way to this with lambdas like I tried?
The error happens because your lambda has non-copyable captures, making the lambda itself not copyable. std::function requires that the wrapped object be copy-constructible.
If you have control over call_func, make it a template:
template<typename T>
void call_func(T&& func)
{
func();
}
int main()
{
std::fstream fs{"test.txt", std::fstream::out};
auto lam = [fs = std::move(fs)] { const_cast<std::fstream&>(fs).close(); };
call_func(lam);
}
Following is my take on your idea in (2). Since std::function requires the wrapped object to be copy-constructible, we can make our own function wrapper that does not have this restriction:
#include <algorithm>
#include <fstream>
#include <iterator>
#include <utility>
#include <memory>
#include <sstream>
#include <vector>
template<typename T>
void call_func(T&& func) {
func();
}
// All functors have a common base, so we will be able to store them in a single container.
struct baseFunctor {
virtual void operator()()=0;
};
// The actual functor is as simple as it gets.
template<typename T>
class functor : public baseFunctor {
T f;
public:
template<typename U>
functor(U&& f)
: f(std::forward<U>(f))
{}
void operator()() override {
f();
}
};
// In C++17 you don't need this: functor's default constructor can already infer T.
template<typename T>
auto makeNewFunctor(T&& v) {
return std::unique_ptr<baseFunctor>(new functor<T>{std::forward<T>(v)});
}
int main() {
// We need to store pointers instead of values, for the virtual function mechanism to behave correctly.
std::vector<std::unique_ptr<baseFunctor>> functors;
// Generate 10 functors writing to 10 different file streams
std::generate_n(std::back_inserter(functors), 10, [](){
static int i=0;
std::ostringstream oss{"test"};
oss << ++i << ".txt";
std::fstream fs{oss.str(), std::fstream::out};
return makeNewFunctor([fs = std::move(fs)] () mutable { fs.close(); });
});
// Execute the functors
for (auto& functor : functors) {
call_func(*functor);
}
}
Note that the overhead from the virtual call is unavoidable: Since you need functors with different behavior stored in the same container, you essentially need polymorphic behavior one way or the other. So you either implement this polymorphism by hand, or use virtual. I prefer the latter.

Call function on boost::variant regardless of type?

I have a class which has a template:
template<class T = int> class slider;
The class has a void Process(void) method, so, I think it should be callable regarless of the type, return value is void and there are no parameters to it.
As for now I have this code to call process each frame in my application:
//class menu:
typedef boost::variant<std::shared_ptr<slider<int>>,std::shared_ptr<slider<float>>,std::shared_ptr<slider<double>>,std::shared_ptr<slider<char>>> slider_type;
std::map<std::string,slider_type> Sliders;
//buttons ... etc ...
void Process()
{
if(!Sliders.empty())
{
for(auto i = Sliders.begin(); i != Sliders.end(); ++i)
{
switch(i->second.which())
{
case 0://slider<int>
{
boost::get<std::shared_ptr<slider<int>>>(i->second)->Process();
break;
}
case 1://slider<float>
{
boost::get<std::shared_ptr<slider<float>>>(i->second)->Process();
break;
}
//.....
}
}
}
}
Is it possible to execute the functions Process() like in the following example?
for(auto i = Sliders.begin(); i != Sliders.end(); ++i)
{
switch(i->second.which())
{
boost::get<???Any???>(i->second)->Process();
}
}
If yes, how?
What would such a function return? You can't change the type of a function at runtime. And the point of a variant is that it's contents are determined at runtime.
The only thing it could return is a boost::any. Which is really just exchanging one kind of unknown for another (an unknown that's a lot harder to deal with when you don't know what it contains, mind you). But if you want to see such a visitor:
struct convert_to_any : public boost::static_visitor<boost::any>
{
template<typename T> boost::any operator() (const T& t) {return t;}
};
Use apply_visitor on that, and you will get an any back. Though I fail to see how that's helpful.
In any case, if you're using get on a variant, you are almost certainly doing the wrong thing. The correct way to access the elements of a variant is with a visitor, not with get.
In your case, the visitor should be simple:
struct ProcessVisitor : public boost::static_visitor<>
{
template<typename T> void operator() (const T& t) const {t->Process();}
};
Just use apply_visitor on that. If the variant contains a type that can be used with operator-> and the return value of that function can have Process called on it, then it will.
(Untested code!)
struct CallProcess : static_visitor<>
{
template <class T>
void operator()(const T &t) const
{
t->Process();
}
};
for(auto i = Sliders.begin(); i != Sliders.end(); ++i)
{
boost::apply_visitor(CallProcess(), i->second);
}
No, not at all. You have to visit and deal with the case of every type. That is much better done with a visitor than your switch hack.
It's not possible because boost::variant has no way to know that all the types in the variant have anything in common. In fact, since the compiler generates a distinct class for each template specialization used, the address of the Process() function that would need to be used is different for each type in the boost::variant. To get around this you could abandon variant and use virtual functions and polymorphic classes sharing a common base class.

How do I iterate over collections generically in C++?

Simply put, if I have a set and vector how do I create a generic method that can handle both as params.
All I want to do, is iterate over either types of collections. Sounds like it should be trivial but I'm missing something.
void printMeSomeStrings(somebaseclass<string> strings) {
for (auto& str : strings) {
cout << str << endl;
}
}
In C#, I would pass IEnumerable or something like that. Then I could iterate over the collection.
Any general reading explaining the answer would be appreciated.
You could use templates. For instance:
#include <iostream>
template<typename C>
void foo(C const& c)
{
std::cout << "{ ";
for (auto const& x : c)
{
std::cout << x << " ";
}
std::cout << "}";
}
And here is how you would use it:
#include <set>
#include <vector>
int main()
{
std::vector<int> v = {1, 2, 3};
foo(v);
std::cout << std::endl;
std::set<std::string> s = {"Hello,", "Generic", "World!"};
foo(s);
}
Live example.
This is exactly what iterators were designed for.
template <class It>
void print_some_strings(It first, It last) {
while (first != last)
std::cout << *first++ << '\n';
}
The first option is to put the code doing the iterating in a template. This requires exposing the implementation to everyone who uses it, which has disadvantages.
Basically, take a type C as a template parameter, then write your code in terms of that type C.
template<typename C>
void printMeSomeStrings(C&& strings) {
for (auto const& str : strings) {
cout << str << endl;
}
}
If you want to be able to have a strong barrier between interface and implementation, the C++11 approach would be to engage in type erasure on a for-iterable container, and then expose a for-iterable container, like how std::function works.
This is trickier. I personally find writing a for_each function easier than writing a full blown iteration adapter. If you want the full blown container iteration type erasure object, start with boost, or ask me below and I might do it.
The for_each adaptor is easy, however.
#include <functional>
#include <utility>
#include <iterator>
#include <memory>
template<typename T>
struct for_each_helper_interface {
virtual ~for_each_helper_interface() {}
virtual void for_each( std::function< void(T) > const& ) = 0;
};
template<typename C, typename T>
struct for_each_helper:for_each_helper_interface<T> {
C& c;
for_each_helper( C& in ):c(in) {}
virtual void for_each( std::function< void(T) > const& f ) override final {
for( auto&& x:c ) {
f(x);
}
}
};
template<typename T>
struct for_each_adaptor {
std::unique_ptr<for_each_helper_interface<T>> pImpl;
void for_each( std::function< void(T) > const& f ) {
if (pImpl) {
pImpl->for_each(f);
}
}
template<typename C>
for_each_adaptor( C&& c ): pImpl( new for_each_helper<C, T>( std::forward<C>(c) ) ) {}
};
which will type-erase the container of T (or a type convertible to T!) and expose a for_each method that lets you iterate over the contents of the container. Use like this:
#include <set>
#include <iostream>
#include <vector>
void print_stufF( for_each_adaptor<std::string const&> c ) {
c.for_each([&](std::string const&s){
std::cout << s << "\n";
});
}
int main() {
std::set<std::string> s;
s.insert("hello");
s.insert("world");
print_stuff(s);
std::vector<std::string> v;
v.push_back("hola");
v.push_back("bola");
print_stuff(v);
}
What is going on here is that for each type used to construct our adaptor, we build a custom implementation of for each. We then store a pointer to the abstract base class of this custom class, and redirect for each calls to it.
This means anything that specializes std::begin or defines its own begin need not be related: we create ad hoc relationships at point of use instead.
Live example: http://ideone.com/xOqBkI
In C#, I would pass IEnumerable or something like that.
C++ uses the more pythonic approach of duck typing to define interfaces(generally called a concept in C++), rather than using inheritance. To do duck typing in C++, you use a template function like this:
template<typename C>
void printMeSomeStrings(const C& strings)
{
for (const auto& str : strings)
{
cout << str << endl;
}
}
In python, duck typing is done at runtime, but in C++ it is done at compile time, so there is no runtime cost to duck typing, and everything is checked at compile time as well.
Here is more info about C++, to help with looking for information. First, the equivalent of the IEnumerator<T> is the iterator in C++. Here is a page about the different iterator categories, and what needs to be implemented for iterators. For legacy reasons, iterators are modeled after pointers in C, which lets you use C arrays with the standard C++ algorithms.
However, unlike IEnumerator<T>, iterators must come in pairs. An iterator to the begining and the end(which is one past the last element). So, the equivalent of IEnumerable<T> in C++ is called a range. In C++11, a range is defined by two free functions, begin(T) and end(T)(it can also be implemented as member function .begin() and .end()).
By defining the concept(aka interface) as two free function, as opposed to using inheritance, ranges can be implemented non-intrusively. So for example, if you have work with some legacy api that uses C style linked lists. They can now be adapted as a C++11 range and used inside a C++ for loop.

Best practice for local variable scope in a C++ callback

I have a functioning C++ callback function, triggered by a user 'mouse down' event. (The IDE is VS2010.)
With each call, I'd like to increment a simple count variable that is local to the callback's scope. Simply put, what is the 'best practices' way to do this?
Thanks in advance for any opinions or directives.
Replace your callback function with a functor - they can store state. An example functor:
#include <iostream>
#include <memory>
class Functor
{
private:
std::shared_ptr<int> m_count;
public:
Functor()
: m_count(new int(0))
{}
void operator()()
{
++(*m_count);
// do other stuff...
}
int count() const
{
return *m_count;
}
};
template <typename F>
void f(F callback)
{
// do stuff
callback();
// do other stuff
}
int main()
{
Functor callback;
f(callback);
f(callback);
std::cout << callback.count(); // prints 2
return 0;
}
Note the use of a shared_ptr inside the functor - this is because f has a local copy of the functor (note the pass-by-value) and you want that copy to share its int with the functor to which you have access. Note also that f has to take its argument by value, since you want to support all callables, and not just functors.