how to get rid of lambda syntax - c++

I need to make those function in the "normal" syntax. how do i change it?
template <template <class, class> class Container>
typename const Container<Course*, std::allocator<Course*> > Schedule<Container>::getAllCourses( ) const
{
Container<Course*, std::allocator<Course*> > newone;
std::for_each(courses.begin(), courses.end(), [&newone](Course *c)
{Course* nc = new Course(c->getName(),c->getNumber(), c->getFaculty()); newone.push_back(nc);});
//make a container and push into it every course
return newone;
}
actually, I need to change the function "for_each" that it will use outside class.
I don't know how to do it. can you help?

A lambda function is a closure type, implemented as an unnamed functor.
You could look into those keywords, to understand how to perform a "conversion". Pretty much the rule would be that this lambda :
[capture_clause](args) -> return_type { /* lambda_body */ }
is practically (in a simplified view - generic lambdas or value/ref captures not explicitly shown here) this
struct no_name
{
no_name(capture_clause) : /* Initialize the closure */ { }
return_type operator()(args) { /* lambda_body */ }
};
In your case, you'd have to a make a class like the following :
template <template <class, class> class Container>
struct lamda_fun
{
Container<Course*, std::allocator<Course*> > &newone;
lamda_fun(Container<Course*, std::allocator<Course*> > &newone)
: newone(newone) {
}
void operator()(Course *c) {
Course* nc = new Course(c->getName(),c->getNumber(), c->getFaculty());
newone.push_back(nc);
}
};
If you still want to get rid of the lambda syntax call it like
std::for_each(courses.begin(), courses.end(), lamda_fun<Container>(newone));
Even though a copy of the functor will be passed to for_each, the functor wraps a reference so the correct thing will be done.
An easier way would be to just use a for loop though (yes those still exist)
// range based version
for (auto c : courses) {
Course* nc = new Course(c->getName(), c->getNumber(), c->getFaculty());
newone.push_back(nc);
}
// traditional version
for (auto it = courses.begin(), ite = courses.end(); it != ite; ++it)
{
auto c = *it;
Course* nc = new Course(c->getName(), c->getNumber(), c->getFaculty());
newone.push_back(nc);
}

You might replace the lambda with a local class:
#include <algorithm>
#include <iostream>
#include <vector>
template <class Container>
Container transform(const Container& container) {
struct Lambda {
Container& result;
Lambda(Container& result) : result(result) {}
void operator () (const typename Container::value_type& value) {
result.push_back(value + 1);
}
};
Container result;
std::for_each(container.begin(), container.end(), Lambda(result));
return result;
}
int main() {
std::vector<int> u;
u.push_back(0);
u.push_back(1);
u.push_back(2);
std::vector<int> v = transform(u);
std::cout << v[0] << v[1] << v[2] << '\n';
}

Related

Setting type of an outer variable using auto lambda parameters

I am using a C++ web framework that heavily uses callback lambda functions. As you may guess, parameters to lambdas are usually specified as auto due to the must to declare very long declarations.
Now I use decltype() operator to find the right type deduced by auto so that I can declare a vector of the same type. When the vector declaration happens inside the lambda, everything is fine.
Where my problem starts is this vector needs to be declared in an outer scope using lambdas auto parameters' type information. Below is a simple example:
std::vector<T> vec; // I want the type information to be inferred just like vec2 from lambda below
auto func = [](auto parameter){
std::vector<decltype(parameter)> vec2; // No problem here.
};
Is this possible?
UPDATE:
The framework I am using is uWebSockets. Here is the example code :
using DataType = std::string;
// I had to go get type information from the source code.
static std::vector<uWS::WebSocket<false, true, DataType> *> users;
uWS::App app {};
app.ws<DataType>("/*", {
.open = [](auto * ws){
// This is also doable
// But not accessible in other lambdas.
static std::vector<decltype(ws)> users2;
// users2.push_back(ws);
users.push_back(ws);
ws->subscribe("sensors/+/house");
},
.close = [](auto *ws, int code, std::string_view message){
users.erase(std::remove(users.begin(), users.end(), ws), users.end());
// Not possible because not accessible.
//users2.erase(std::remove(users2.begin(), users2.end(), ws), users2.end());
std::cout << "Client disconnected!" << std::endl;
},
.message = [](auto *ws, std::string_view message, uWS::OpCode opCode){
try{
std::string message2 = std::string(message) + std::string(" ACK");
for(const auto & ws2 : users)
if(ws != ws2)
ws2->send(message2, opCode);
}catch(std::exception& e){
std::cout << e.what() << std::endl;
}
},
});
Now, nowhere in the main.cpp, there is a need to pass a parameter to lambda functions. That's where the main problem comes from.
The problem here is that auto has no type until it is used, auto make it a template call operator:
#include <iostream>
using namespace std;
int main()
{
auto func = [](auto param){
std::cout << param << std::endl;
};
func(4); // integer call
func("lol"); //const char* call
return 0;
}
The consequence is that param could have any arbitrary type, before we are looking at a specific usage.
If you know the argument which will be provided, then decltype can be applied:
#include <iostream>
using namespace std;
int main()
{
int arg1 = 4;
using Type1 = decltype(arg1); // type for the argument
auto func = [](auto param){
std::cout << param << std::endl;
};
func(arg1); // Type1 call
func("lol"); //const char* call
return 0;
}
You have to manually look at the type that you are initialising.
A generic lambda creates an object with a template operator(). There's not much stopping there from being multiple instantiations of that template.
If that's the case then there isn't a type that is the type of auto parameter.
You are relatively lucky here, in that the object you are initialising with all these functor members puts the arguments right in it's definition:
MoveOnlyFunction<void(WebSocket<SSL, true, UserData> *)> open = nullptr;
If you don't want to look at the definitions again, you could write a trait
template<typename Signature>
struct MoveOnlyFunctionTraits;
template <typename R, typename... Arguments>
struct MoveOnlyFunctionTraits<MoveOnlyFunctionTraits<R(Arguments...)> {
using result_type = R;
static constexpr auto arity = sizeof...(Arguments);
template <std::size_t I>
using argument = std::tuple_element_t<std::tuple<Arguments...>, I>;
}
template<typename Signature, std::size_t I>
using argument_t = typename MoveOnlyFunctionTraits<Signature>::template argument<I>;
That allows you to pull out the type
using websocket_type = argument_t<decltype(uWS::App::WebSocketBehaviour<DataType>::open), 0>;
std::vector<websocket_type> users;
Or you could submit a pull request to the library, that exposes type aliases you are interested in
template <bool SSL>
struct TemplatedApp {
// existing members ...
public:
template <typename DataType>
using websocket_type = WebSocket<SSL, true, DataType>;
};
Then
std::vector<uWS::App::template websocket_type<DataType> *> users;
Or maybe you could use templates.
#include <vector>
template<typename type_t>
void some_function(const type_t value)
{
std::vector<type_t> vec;
auto func = [](const type_t& parameter)
{
std::vector<type_t> vec2;
};
//....
}
auto get_something()
{
// some made up complex data type returned as auto
using some_complex_data_type_from_somewhere_t = std::vector<std::vector<int>>;
some_complex_data_type_from_somewhere_t value{};
return value;
}
int main()
{
auto value = get_something();
some_function(value);
return 0;
}
You can "front-load" the type inference into a type alias.
void some_function() {
using value_type = decltype(infer_from_somewhere);
// alt: using value_type = typename some::annoyingly<complex>::type;
std::vector<value_type> vec;
auto func = [](value_type parameter){
std::vector<value_type> vec2;
};
//...
}

calling same funtion with different types of argument

I want to call a function which can accept a vector but i want to pass different type of vector to that function.
I have come across a function call like
print<int>(int_vector);
print<string>(string_vector);
here <int> and <string> are mention as what.
One more doubt is if i pass different type of vector also how can i take it in the function call. should i use void * ? then type cast it
Sample of func template
#include <iostream>
#include <vector>
using namespace std;
template<typename T>
void foo(std::vector<T> vec)
{
// do stuff with vector
}
int main() {
std::vector<int> iv = {42};
foo(iv);
std::vector<string> sv = {"hello"};
foo(sv);
return 0;
}
There is an alternative if you know the exact types:
void foo(std::vector<int> v)
{}
void foo(std::vector<string> v)
{}
This is plain function overloading.
What you want to use here is a templated function. Simples example relevant to your question would be:
// This line says that the function accepts one generic type
// which you will refer to as T
template <typename T>
// vector<T> means that the referenced type T will be of the type the vector,
// you call this function with, is templated with
void print(const std::vector<T>& data) {
// Here calling the operator[] will return the generic type T
const T& element = data[0];
for (unsigned i = 0; i < data.size(); ++i)
std::cout << data[i] << std::endl;
}
This function would be used like this:
std::vector<int> vec = { 1, 2, 3 };
print(vec);
// Note that you don't need to write the template type here
// because it is deduced from the type of vector
And the output will be:
1
2
3
The code is using template programming to make a generic function:
template <typename T>
void foo(T item){
// do something to item of type T
}
void foo(int str); // Declare a certain type of template
Later you can use the function:
int x = 1;
foo<int>(x);
But in this case, because e.g. printf uses different formatting for different types, it might be wise to instead overload the functions. Overloading is the practise of naming functions similarly, but giving different arguments:
void foo(std::vector<int> v);
void foo(std::vector<string> v);
This concept is known as generic programming. In C++, you use templates to achieve this, and specifically a function template. If you want different types of lists with different types to be auto-deduced, or have a specific need for advanced templates, you can also use a template-template.
An example:
#include <iostream>
#include <vector>
#include <list>
template < template < class, class > class V, class T, class A >
void erase_value(V<T, A>& v, const T& t)
{
typename V<T,A>::iterator s = v.begin();
while (s != v.end()) {
if ((*s) == t) { v.erase(s); break; }
++s;
}
}
template < typename T >
void print_all(T begin, T end)
{
for (; begin != end; ++begin) {
std::cout << *begin << " ";
}
std::cout << std::endl;
}
template < typename T >
void print_all(const T& array)
{
for (auto i : array) {
std::cout << i << " ";
}
std::cout << std::endl;
}
int main(int argc, char** argv)
{
std::vector<std::string> strings {"123","321","ABC"};
std::list<int> ints {123,321,5332};
print_all(strings);
print_all(ints);
erase_value(strings, std::string("123"));
erase_value(ints, 123);
print_all(strings.begin(), strings.end());
print_all(ints.begin(), ints.end());
return 0;
}
Hope that can help.
I believe you're looking for ostream_iterator:
template <typename T>
void print(vector<T> arg){
copy(cbegin(arg), cend(arg), ostream_iterator<T>(cout, " "));
}

How do you create a generic parser using qi?

I am attempting to create generic parser-elements using qi as I unfortunately (MSVC must be supported) can not use X3.
The idea is to have a templated struct:
template<class T> struct parse_type;
Which I could use like this:
template<class T> T from_string(std::string const& s)
{
T res;
parse_type<T> t;
...
if (phrase_parse(...,parse_type<T>(),...,t))
}
or specialise like this
template<class T,class Alloc>
struct parse_type<std::vector<T,Alloc>>
{
// Parse a vector using rule '[' >> parse_type<T> % ',' > ']';
}
The primary purpose is to allow for easy parsing of e.g. std::tuple, boost::optional and boost::variant (The last one can not be automatic due to the greedy nature of qi).
I would appreciate feedback as to how approach this. Currently I base my struct on qi::grammar, but grammar is not supported in X3 and I would like to use X3 when MSVC compiles this, and I am also a little bit uncomfortable with having to provide the skipper.
An alternative would be to have a static function in parse_type that returns the appropriate rule. I am considering if this is a cleaner approach?
Any feedback will be appreciated.
Update2: Replaced code-snippet with compilable example that fails at runtime. Here is the code:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
#include <string>
#include <iostream>
#include <iostream>
// Support to simplify
using iter = std::string::const_iterator;
void print(std::vector<int> const& v)
{
std::cout << '[';
for (auto i: v) std::cout << i << ',';
std::cout << "]";
}
namespace qi = boost::spirit::qi;
// My rule factory - quite useless if you do not specialise
template<class T> struct ps_rule;
// An example of using the factory
template<class T>
T from_string(std::string const& s)
{
T result;
iter first { std::begin(s) };
auto rule = ps_rule<T>::get();
phrase_parse(first,std::end(s),rule,qi::space,result);
return result;
}
// Specialising rule for int
template<>
struct ps_rule<int>
{
static qi::rule<iter,int()> get() { return qi::int_; }
};
// ... and for std::vector (where the elements must have rules)
template<class T,class Alloc>
struct ps_rule<std::vector<T,Alloc>>
{
static qi::rule<iter,std::vector<T,Alloc>()> get()
{
qi::rule<iter,std::vector<T,Alloc>()> res;
res.name("Vector");
res =
qi::lit('{')
>> ps_rule<T>::get() % ','
>> '}';
return res;
}
};
int main()
{
// This one works like a charm.
std::cout << ((from_string<int>("100") == 100) ? "OK\n":"Failed\n");
std::vector<int> v {1,2,3,4,5,6};
// This one fails
std::cout << ((from_string<std::vector<int>>("{1,2,3,4,5,6}") == v) ? "OK\n":"Failed\n");
}
The code fails in boost/function_template.hpp line 766:
result_type operator()(BOOST_FUNCTION_PARMS) const
{
if (this->empty())
boost::throw_exception(bad_function_call());
return get_vtable()->invoker
(this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS);
}
This code is a member function in boost::function4
,boost::fusion::vector0 > &
,boost::spirit::unused_type const&>
and the problem is that get_vtable returns an invalid pointer.
Your main problem is that the copy constructor for qi::rule takes a reference to the original rule, which in your case is a local variable. One way you can avoid this problem is by using qi::rule's copy member function but this requires changing slightly the return type of your specialization of ps_rule.
static typename boost::proto::terminal<qi::rule<iter,std::vector<T,Alloc>()>>::type get()
{
//[...] (same as before)
return res.copy();
}
Once you do that, the same problem arises with your ps_rule<int> even though it seemed to work in isolation. You could do something analogous but in this case the rule is not required, it would be better (even from a performance point of view) to just use something like:
static qi::int_type get() { return qi::int_; }
Full Sample (Running on WandBox)
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iostream>
// Support to simplify
using iter = std::string::const_iterator;
void print(std::vector<int> const& v)
{
std::cout << '[';
for (auto i: v) std::cout << i << ',';
std::cout << "]";
}
namespace qi = boost::spirit::qi;
// My rule factory - quite useless if you do not specialise
template<class T> struct ps_rule;
// An example of using the factory
template<class T>
T from_string(std::string const& s)
{
T result;
iter first { std::begin(s) };
auto rule = ps_rule<T>::get();
qi::phrase_parse(first,std::end(s),rule,qi::space,result);
return result;
}
// Specialising rule for int
template<>
struct ps_rule<int>
{
static qi::int_type get() { return qi::int_; }
};
// ... and for std::vector (where the elements must have rules)
template<class T,class Alloc>
struct ps_rule<std::vector<T,Alloc>>
{
static typename boost::proto::terminal<qi::rule<iter,std::vector<T,Alloc>()>>::type get()
{
qi::rule<iter,std::vector<T,Alloc>()> res;
res.name("Vector");
res =
qi::lit('{')
>> ps_rule<T>::get() % ','
>> '}';
return res.copy();
}
};
int main()
{
// This one works like a charm.
std::cout << ((from_string<int>("100") == 100) ? "OK\n":"Failed\n");
std::vector<int> v {1,2,3,4,5,6};
std::cout << ((from_string<std::vector<int>>("{1,2,3,4,5,6}") == v) ? "OK\n":"Failed\n");
std::vector<std::vector<int> > vv {{1,2,3},{4,5,6}};
std::cout << ((from_string<std::vector<std::vector<int>>>("{{1,2,3},{4,5,6}}") == vv) ? "OK\n":"Failed\n");
}
PS: You can save lots of specializations if you use Spirit's own machinery to create parsers automatically in your primary template. Here is an example.

Inserting a variadic argument list into a vector?

Forgive me if this has been answered already, as I couldn't find it...
Basically I have an object that needs to take a variadic argument list in it's constructor and store the arguments in a vector. How do I initialize a vector from a the arguments of a variadic constructor?
class GenericNode {
public:
GenericNode(GenericNode*... inputs) {
/* Something like... */
// inputs_.push_back(inputs)...;
}
private:
std::vector<GenericNode*> inputs_;
};
The best thing would be to use an initializer list
#include <initializer_list>
#include <vector>
class GenericNode {
public:
GenericNode(std::initializer_list<GenericNode*> inputs)
:inputs_(inputs) {} //well that's easy
private:
std::vector<GenericNode*> inputs_;
};
int main() {
GenericNode* ptr;
GenericNode node{ptr, ptr, ptr, ptr};
} //compilation at http://stacked-crooked.com/view?id=88ebac6a4490915fc4bc608765ba2b6c
The closest to what you already have, using C++11 is to use the vector's initializer_list:
template<class ...Ts>
GenericNode(Ts... inputs)
:inputs_{inputs...} {} //well that's easy too
//compilation at http://stacked-crooked.com/view?id=2f7514b33401c51d33677bbff358f8ae
And here's a C++11 version with no initializer_lists at all. It's ugly, and complicated, and requires features missing from many compilers. Use the initializer list
template<class T>
using Alias = T;
class GenericNode {
public:
template<class ...Ts>
GenericNode(Ts... inputs) { //SFINAE might be appropriate
using ptr = GenericNode*;
Alias<char[]>{( //first part of magic unpacker
inputs_.push_back(ptr(inputs))
,'0')...,'0'}; //second part of magic unpacker
}
private:
std::vector<GenericNode*> inputs_;
};
int main() {
GenericNode* ptr;
GenericNode node(ptr, ptr, ptr, ptr);
} //compilation at http://stacked-crooked.com/view?id=57c533692166fb222adf5f837891e1f9
//thanks to R. Martinho Fernandes for helping me get it to compile
Unrelated to everything, I don't know if those are owning pointers or not. If they are, use std::unique_ptr instead.
// inputs_.push_back(inputs)...;
This doesn't work because you can't expand a parameter pack as a statement, only in certain contexts such as a function argument list or initializer-list.
Also your constructor signature is wrong, if you're trying to write a variadic template it needs to be a template!
Once you write your constructor signature correctly the answer is easy, just construct the vector with the pack expansion:
#include <vector>
class GenericNode
{
public:
template<typename... T>
GenericNode(T*... inputs) : inputs_{ inputs... }
{ }
private:
std::vector<GenericNode*> inputs_;
};
(You could instead have set it in the constructor body with:
inputs_ = { inputs... };
but the cool kids use member initializers not assignment in the constructor body.)
The downside of this solution is that the template constructor accepts any type of pointer arguments, but will then give an error when trying to construct the vector if the arguments aren't convertible to GenericNode*. You could constrain the template to only accept GenericNode pointers, but that's what happens automatically if you do what the other answers suggest and make the constructor take a std::initializer_list<GenericNode*>, and then you don't need any ugly enable_if SFINAE tricks.
You can't use a variadic argument list unless it's a template, you can, as stated, use a initializer_list like this:
class GenericNode {
public:
GenericNode(std::initializer_list<GenericNode*> inputs) : inputs_(inputs)
{
}
private:
std::vector<GenericNode*> inputs_;
};
template <class ... T>
GenericNode* foo(T ... t)
{
return new GenericNode({t...});
}
class Blob
{
std::vector<std::string> _v;
public:
template<typename... Args>
Blob(Args&&... args)
: _v(std::forward<Args>(args)...)
{ }
};
int main(void)
{
const char * shapes[3] = { "Circle", "Triangle", "Square" };
Blob b1(5, "C++ Truths");
Blob b2(shapes, shapes+3);
}
Example from C++11 Truths looks simple enough...;)
Not a complete solution but might give you some ideas.
Another way to do it:
#include <iostream>
#include <vector>
using std::vector;
template <typename T>
void variadic_vector_emplace(vector<T>&) {}
template <typename T, typename First, typename... Args>
void variadic_vector_emplace(vector<T>& v, First&& first, Args&&... args)
{
v.emplace_back(std::forward<First>(first));
variadic_vector_emplace(v, std::forward<Args>(args)...);
}
struct my_struct
{
template <typename... Args>
my_struct(Args&&... args)
{
variadic_vector_emplace(_data, std::forward<Args>(args)...);
}
vector<int>& data() { return _data; }
private:
vector<int> _data;
};
int main()
{
my_struct my(5, 6, 7, 8);
for(int i : my.data())
std::cout << i << std::endl;
}
I recently wrote the following function that takes a string with
{1} , {2} , {3} ... in it and substitutes the argument list. I ran in to the same problem until I decided to let the compiler work it out for itself with the auto keyword.
#include <string>
#include <vector>
using std::string;
using std::vector;
template<typename S, typename... Args>
string interpolate( const S& orig , const Args&... args)
{
string out(orig);
auto va = {args...};
vector<string> v{va};
size_t i = 1;
for( string s: v)
{
string is = std::to_string(i);
string t = "{" + is + "}";
try
{
auto pos = out.find(t);
if(pos != out.npos)
{
out.erase(pos, t.length());
out.insert( pos, s);
}
i++;
}
catch( std::exception& e)
{
std::cerr << e.what() << std::endl;
}
} // for
return out;
}
Apparently that is good enough as long as the types line up correctly.
In this case I am using only std::string throughout.
I think this is an elegant technique, but it may have drawbacks.
Note: If the element-type of a vector is not copy-initializable (it is in OP post), the std::initializer list route will not work.
You can still use a variadic unpack statement (post C++ 17):
(inputs_.emplace_back(std::move(args)), ...);

Convert void* to std::function<void()>

Is store function pointers with different parameters in a vector of void pointers.
unordered_map<string, vector<void*> > List;
template <typename T>
void Listen(string Name, function<void(T)> Function)
{
List[Name].push_back(&Function);
}
Then I want to call them, assuming that T is the same type for Fire as used for the Listen.
template <typename T>
void Fire(string Name, T Data)
{
auto Functions = List[Name];
for (auto i = Functions.begin(); i != Functions.end(); ++i)
{
(function<void(T)>)i)(Data);
}
}
But I get a compiler error which reads error C2064: term does not evaluate to a function taking 1 arguments in file ...\vc\include\xrefwrap 431 1.
What am I doing wrong?
For one, you're taking the address of a parameter, here:
List[Name].push_back(&Function);
Then you're trying to convert an iterator object to a std::function object here:
(function<void(T)>)i)
What you trying to do can be done, like this, although it's not pretty, to put it mildly:
unordered_map<string, vector<void*> > List;
template <typename T>
void Listen(string Name, function<void(T)> &Function)
{
List[Name].push_back(&Function);
}
template <typename T>
void Fire(string Name, T Data)
{
auto Functions = List[Name];
for (auto i = Functions.begin(); i != Functions.end(); ++i)
{
function<void(T)> *ptr = *i;
(*ptr) (Data);
}
}
It can break in lot of ways, for example you have no control that the function, registered under some name in Listen is called with the correct argument in Fire - consider calling Listen<int> ("foo", f); and then doing Fire<double> ("foo", 3.14);
Another approach - just pass closures for callbacks:
unordered_map<string, std::vector<function<void()> > > List;
void Listen(string Name, function<void()> Function)
{
List[Name].push_back(Function);
}
void Fire(string Name)
{
auto Functions = List[Name];
for (auto i = Functions.begin(); i != Functions.end(); ++i)
(*i) ();
}
#include <functional>
#include <unordered_map>
#include <memory>
#include <string>
#include <vector>
template<typename T> struct BlockDeduction{typedef T type;};
struct BaseCallback {
virtual ~BaseCallback();
template<typename T>
void DoCall( typename BlockDeduction<T>::type&& t ) const;
};
template<typename T>
struct Callback: BaseCallback
{
std::function<void(T)> func;
Callback( std::function<void(T)> const& f ):func(f) {}
};
template<typename T>
void BaseCallback::DoCall( typename BlockDeduction<T>::type&& t ) const {
Assert( dynamic_cast<Callback<T>const*>(this) );
static_cast<Callback<T>const*>(this).func(std::forward(t));
}
typedef std::unique_ptr<BaseCallback> upCallback;
template<typename T>
upCallback make_callback( std::function<void(T)> const& f ) {
return upCallback( new Callback<T>( f ) );
}
struct Listener {
std::unordered_map< std::string, std::vector<upCallback>> List;
template<typename T>
void Listen( std::string Name, std::function<void(T)> f) {
List[Name].push_back( make_callback(f) );
}
template<typename T>
void Fire( std::string Name, typename BlockDeduction<T>::type&& t ) {
auto callbacks = List.find(Name);
if (callbacks == List.end()) return;
for(auto it = callbacks->second.begin(); it != callbacks->second.end(); ++it) {
if (it +1 = callbacks->second.end())
{
(**it).DoCall<T>( std::forward(t) );
} else {
(**it).DoCall<T>( t );
}
}
}
};
... or something like that.
This stores a copy of the std::function in the map, wrapped up generically. Memory is handled via a unique_ptr. I carefully blocked type deduction at points where the type must be exactly what you used when you installed the Listener (automatic type deduction at that point is rather fragile).
In debug, you'll get an assertion failure if you violate the Name<->type mapping.
Some extra work needs to be done for nullary callbacks. Just write a DoCall that casts BaseCallback to Callback<void>, specialize Callback<void> to be a nullary function wrapper, specialize make_callback on nullary function, and write a Fire(string) method for Listener that calls the bare DoCall.
Or create a struct Empty and use lambdas to wrap nullary functions in function<void(Empty)>, which would involve slightly less code, but would be slower at run-time.