Skip to content

Instantly share code, notes, and snippets.

@austo
Last active July 29, 2017 17:01
Show Gist options
  • Select an option

  • Save austo/5676ce0a1bfd129d992d4f1b79868eef to your computer and use it in GitHub Desktop.

Select an option

Save austo/5676ce0a1bfd129d992d4f1b79868eef to your computer and use it in GitHub Desktop.
call based on type
#include <functional>
#include <iostream>
#include <string>
#include <vector>
// clang++ -std=c++11 -stdlib=libc++ -Wall handler_wrap.cpp -o handler_wrap
// g++ -std=c++11 -Wall handler_wrap.cpp -o handler_wrap
// Message Type #1
class Foo {
std::string d_payload;
public:
Foo(const std::string& payload) : d_payload(payload) {}
const std::string& payload() const { return d_payload; }
enum { TYPE_ID = 1 };
};
// Message Type #2
class Bar {
int d_weight;
std::string d_payload;
public:
Bar(const std::string& payload)
: d_weight(payload.length()), d_payload(payload) {}
const std::string& payload() const { return d_payload; }
const int& weight() const { return d_weight; }
enum { TYPE_ID = 2 };
};
// "Raw" message
struct Blob {
int d_type_id;
std::string d_payload;
Blob(int type_id, std::string payload)
: d_type_id(type_id), d_payload(payload) {}
};
// Wrapper with consistent interface
template <typename T>
class HandlerWrapper {
std::function<void(T&)> m_handler;
public:
explicit HandlerWrapper(std::function<void(const T&)> handler)
: m_handler(handler) {}
void operator()(const Blob& blob) {
if (blob.d_type_id == T::TYPE_ID) {
T msg(blob.d_payload);
m_handler(msg);
}
}
};
class Registry {
std::vector<std::function<void(const Blob&)>> m_handlers;
public:
Registry() : m_handlers() {}
// Single registration function (w/overload for raw function pointers)
template <typename T>
Registry& addHandler(std::function<void(const T&)> handler) {
m_handlers.emplace_back(HandlerWrapper<T>(handler));
return *this;
}
template <typename T>
Registry& addHandler(void (*handler)(const T&)) {
return addHandler(std::function<void(const T&)>(handler));
}
void call(std::vector<Blob> blobs) {
for (auto it = blobs.begin(); it != blobs.end(); ++it) {
for (auto f = m_handlers.begin(); f != m_handlers.end(); ++f) {
(*f)(*it);
}
}
}
};
// Backing function (would most likely be a mem_fun reference)
void fooHandler(const Foo& foo) {
std::cout << "Foo: " << foo.payload() << std::endl;
}
void barHandler(const Bar& bar) {
std::cout << "Bar: (" << bar.payload() << ", " << bar.weight() << ")"
<< std::endl;
}
int main(int argc, char** argv) {
std::vector<Blob> blobs{Blob(1, "Blob 1"), Blob(2, "Blob 2"),
Blob(1, "Blob 3"), Blob(2, "Blob 4")};
Registry r1;
std::cout << "With raw function pointers:" << std::endl;
r1.addHandler(&fooHandler).addHandler(&barHandler).call(blobs);
// Client responsible for creating these from whatever
std::function<void(const Foo&)> f1(fooHandler);
std::function<void(const Bar&)> f2(barHandler);
Registry r2;
std::cout << "\nWith std::functions:" << std::endl;
r2.addHandler(f1).addHandler(f2).call(blobs);
std::function<void(const Bar&)> f3([](const Bar& b) {
std::cout << "Bar lambda -> ";
barHandler(b);
});
Registry r3;
std::cout
<< "\nWith mix of raw function pointers, std::functions and lambdas:"
<< std::endl;
r3.addHandler(fooHandler)
.addHandler(f1)
.addHandler(barHandler)
.addHandler(f3)
.call(blobs);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment