I have a Signal
class in my application that provides classes with an option to expose events (same as in .NET).
The class works and all is well.
Yesterday I saw this SO question (and its answer) and was familiarized with std::forward
.
I decided to try to use it in my code so I changed every std::function<void(Args...)>
to std::function<void(Args&&...)>
and in the raise function (the operator()
) I used the same logic I saw in the above link so now the function takes Args&&...args
and the callback uses std::forward<Args>(args)...
Here's a simplified version of my Signal class (with some changes to make it a good example):
template<typename... Args> class Signal
{
public:
int operator+=(const std::function<void(Args&&...)>& func) {
int token = getNewToken();
m_subscribers.emplace(token, func);
return token;
}
void operator()(Args&&... args) {
for (auto it : m_subscribers) {
it.second(std::forward<Args>(args)...);
}
}
private:
std::map<int, std::function<void(Args&&...)>> m_subscribers;
};
int main() {
int* six = new int(6);
int seven = 7;
Signal<int*> e1;
e1 += [](int* x) { std::cout << *x; };
Signal<int> e2;
e2 += [](int x) { std::cout << x; };
e1(&seven);
e2(6);
e1(six); //Error C2664 'void Signal<int *>::operator ()(int *&&)':
// cannot convert argument 1 from 'int *' to 'int *&&'
e1(std::move(six)); //This is a workaround
return 0;
}
The issue I'm seeing is with classes (or main
in this example) that try to raise events with pointers and I'm not sure how to solve this.
My main goal is to have the Signal class a general API and if the developers chose to use Signal<int*>
I don't want him\her to raise with std::move
.
What am I doing wrong here?