How emulate a templatised std::function in C++ - c++

Following is a basic instance of what I am doing in my C++ program. I have a list of listeners which are all std::functions. I have a concept DataType which means what kind of data the listener is interested in. The idea here is the same as publish-subscribe pattern. A method interested in certain kind of data should be able to add itself to the list of listeners using AddListener. Some methods are added & they receive a callback whenever required.
The program works fine !!
#include <iostream>
#include <functional>
#include <vector>
#include <string>
enum class DataType {
Type_1,
Type_2
// and so on
};
typedef std::function<void(std::pair<DataType, std::string>)> MyListenerType;
//template <typename T>
//typedef std::function<void(T>)> MyListenerType;
// How can I emulate the above so that a method passing any kind of primitive data-type namely "int, bool, float or double" can be added into
// my vector of listners.
std::vector<MyListenerType> my_data_listeners_1;
std::vector<MyListenerType> my_data_listeners_2;
void ListenerMethod_Instance_1(std::pair<DataType, std::string> information) {
DataType data_type = information.first;
std::string message = information.second;
std::cout << "ListenerMethod_Instance_1 called with message " << message << "\n";
}
void ListenerMethod_Instance_2(std::pair<DataType, std::string> information) {
DataType data_type = information.first;
std::string message = information.second;
std::cout << "ListenerMethod_Instance_2 called with message " << message << "\n";
}
void AddListener (MyListenerType listener, DataType type_of_interest) {
if (DataType::Type_1 == type_of_interest) {
my_data_listeners_1.push_back(listener);
std::cout << "Added a method instance for DataType::Type_1" << "\n";
}
else if (DataType::Type_2 == type_of_interest) {
my_data_listeners_2.push_back(listener);
std::cout << "Added a method instance for DataType::Type_2" << "\n";
}
else {
std::cout << "Listener type not supported" << "\n";
}
}
void CallAllListnersWhohaveSuscribed() {
if (!my_data_listeners_1.empty()) {
std::string send_message_1 = "some message 123";
std::pair <DataType, std::string> info_to_send_1 = std::make_pair (DataType::Type_1, send_message_1);
for(auto const &listener : my_data_listeners_1) {
listener(info_to_send_1);
}
}
if (!my_data_listeners_2.empty()) {
std::string send_message_2 = "some message 456";
std::pair <DataType, std::string> info_to_send_2 = std::make_pair (DataType::Type_2, send_message_2);
for(auto const &listener : my_data_listeners_2) {
listener(info_to_send_2);
}
}
}
int main() {
// Add ListenerMethod_Instance_1 for instance
DataType data_type_1 = DataType::Type_1;
auto listener_instance_1 = std::bind(ListenerMethod_Instance_1, std::placeholders::_1);
AddListener(listener_instance_1, data_type_1);
// Add ListenerMethod_Instance_2 for instance
DataType data_type_2 = DataType::Type_2;
auto listener_instance_2 = std::bind(ListenerMethod_Instance_2, std::placeholders::_1);
AddListener(listener_instance_2, data_type_2);
CallAllListnersWhohaveSuscribed();
return 0;
}
Following is the output of the program:
./stdFunctionTest
Added a method instance for DataType::Type_1
Added a method instance for DataType::Type_2
ListenerMethod_Instance_1 called with message some message 123
ListenerMethod_Instance_2 called with message some message 456
But here is how I want to modify & struggling with. The caveat is that every ListenerMethod_Instance_1 & ListenerMethod_Instance_2 have to parse the pair to get their info which I don't want to. I want to enable a method of any C++ primitive data type be it "int, bool, float or double" to be able to be added into the listeners vector & receive the callback. For example following method should be "add-able" into AddListener.
void ListenerMethod_Instance_3(int integer_data) {
std::cout << "ListenerMethod_Instance_3 called with integer_data " << integer_data << "\n";
}
Looking at this link here looks somewhat possible someway. But I'm struggling to adapt it to my use-case here. Please suggest.
So, basically how can I achieve templates functionality with std::functions ?

struct anything_view_t {
void* ptr=0;
template<class T, std::enable_if_t<!std::is_same<anything_view_t, std::decay_t<T>>{}, int> =0>
anything_view_t(T&&t):ptr(std::addressof(t)){}
anything_view_t()=default;
anything_view_t(anything_view_t const&)=default;
anything_view_t& operator=(anything_view_t const&)=default;
template<class T>
operator T() const { return *static_cast<T*>(ptr); }
};
this is a very unsafe type erasing view of anything.
struct any_callbacks {
std::unordered_map<std::type_index, std::vector<std::function<void(anything_view_t)>>> table;
template<class T>
void add_callback( std::function<void(T)> f ){
table[typeid(T)].push_back(f);
}
template<class T>
void invoke_callbacks(T t) const {
auto it = table.find(typeid(T));
if (it==table.end()) return;
for(auto&&f:it->second)
f(t);
}
};
something like the above should work. The type T must match exactly. References not supported. Code not compiled, design is sound, probably has typos.
This is not restructed to primitive types. You should pass T explicitly, don't rely on deduction as that is fragile.

Related

How can I pass a member function with an unknown prototype to a class in C++?

I need to make a class (we'll call it Command) that takes in a string, processes it into function arguments, and then passes it to a member function of a different class. For my use, the member function that I pass to Command could come from a number of classes, and could have many different prototypes. I can guarantee that that member function will return void. Here's the code I imagine:
class Command {
public:
vector<tuple<int, string, any>> argument_specification;
SomeType callable;
Command(vector<tuple<int, string, any>> argument_spec, SomeType callable) {
this->argument_specification = argument_spec;
this->callable = callable;
}
void apply(string args) {
/* processing args according to this->argument_specification
to make a std::tuple arguments */
std::apply(this->callable, arguments);
}
};
class Action {
public:
print_two_arguments(int arg1, int arg2) {
std::cout << arg1 << ", " << arg2 << std::endl;
}
print_one_arguments(std::string arg1) {
std::cout << arg1 << std::endl);
}
}
int main() {
Action *actor = new Action();
// my argument specification code splits by string and then extracts
// arguments by position or keyword and replacing with a default if
// not specified
Command *command1 = new Command({{0, "first_arg", "something"}},
&actor->print_one_argument);
command1->apply("hello_world"); // Should print "hello_world"
Command *command2 = new Command({{0, "first_arg", 2},
{1, "second_arg", 10}},
&actor->print_two_arguments);
command2->apply("0 2"); // should print "0 2"
}
I don't really mind what method gets there - I've tried std::bind and can't quite get that to work, I've also tried lambdas. I'm currently trying a template class with a type deduced factory method. I'm also open to a macro definition that will fix this at compile time.
A couple ideas come to mind, but the key thing that I'm seeing is that you want to be able to take an arbitrary void function and call it with a single string. Templates can be really helpful here because you can use them to auto-deduce things such as how to build the tuple that you apply to the function.
This will be a semi-complicated meta-program-y solution, but I love that stuff; so I'm going to build a prototype. Also beware, this is the kind of solution that will result in absolutely horrendous compiler errors if you try to use it wrong.
My suggestion would be to make Command a templated type, where the command itself is templated on the parameter types of the function you want to pass it. If you need to be able to make a list of these to apply arguments to, then you can have a base class which provides the apply function. Since I don't fully understand how the argument specification is supposed to work, I'm punting on that and supporting keyword arguments only; but the way I built this, it should be fairly straightfoward to sub in your own argument splitter. I think. It could be cleaner, but I need to get back to my job.
Play with it on Compiler Explorer: https://godbolt.org/z/qqrn9bs1T
#include <any>
#include <functional>
#include <initializer_list>
#include <iostream>
#include <iterator>
#include <memory>
#include <regex>
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
using namespace std;
// Converts the string arguments to the actual types
template <class T> T convert_arg(std::string);
template <> std::string convert_arg<std::string>(std::string s) { return s; }
template <> int convert_arg<int>(std::string s) { return std::stoi(s); }
// Split on spaces
std::vector<string> tokenize(std::string s) {
istringstream iss(s);
return {istream_iterator<string>{iss}, istream_iterator<string>{}};
}
// Argument spec defines how to parse the arguments from the input. It
// contains the positional index in the string, the name of it, and a
// default value. It's effectively a mapping from the string being applied
// to the function being called.
//
// This could maybe be turned into a std::tuple<std::tuple<...>>, but
// I'm not sure. That could get a little messy with trying to iterate
// through it to build the argument list, and I don't think it buys us
// anything.
//
// For example, given the argument spec
// {{1, "first_arg", 0}, {0, "second_arg", "some_default"}}
// You could call a function that has the signature
// void (int, string);
// And you could parse the following argument strings (assuming space-delimited)
// "second_arg=hello first_arg=0"
// "words 1"
// "first_arg=5 more_text"
using argument_spec_t = std::vector<tuple<std::size_t, string, std::string>>;
class CommandBase {
public:
virtual void apply(string args) = 0;
};
// Concrete commands are templated on the argument types of the function
// that they will invoke. For best results, use make_command() to deduce
// this template from the function that you want to pass the Command in
// order to get references and forwarding correct.
template <class... ArgTs> class Command : public CommandBase {
public:
using callable_t = std::function<void(ArgTs...)>;
// Holds the argument specification given during constuction; this
// indicates how to parse the string arguments
argument_spec_t m_argument_specification;
// A function which can be invoked
callable_t m_callable;
Command(argument_spec_t argument_spec, callable_t callable)
: m_argument_specification(std::move(argument_spec)),
m_callable(std::move(callable)) {}
void apply(string args) {
//std::cout << "Apply " << args << std::endl;
std::tuple parsed_args =
build_args(split_args(std::move(args), m_argument_specification),
std::index_sequence_for<ArgTs...>{});
std::apply(m_callable, parsed_args);
}
private:
// Pre-processes the command arguments string into a
// std::unordered_map<size_t, std::string> where x[i] returns the text of the
// i'th argument to be passed to the function.
//
// \todo Support positional arguments
// \todo Be more robust
static std::unordered_map<size_t, std::string>
split_args(std::string args, const argument_spec_t &arg_spec) {
std::unordered_map<std::string, std::string> kw_args;
std::unordered_map<size_t, std::string> arg_map;
vector<string> tokens = tokenize(args);
for (const auto &token : tokens) {
auto delim = token.find("=");
auto key = token.substr(0, delim);
auto val = token.substr(delim + 1);
kw_args[key] = val;
// std::cout << "key = " << val << std::endl;
}
for (size_t i = 0; i < arg_spec.size(); ++i) {
const auto &[pos_index, key, default_val] = arg_spec[i];
auto given_arg_it = kw_args.find(key);
if (given_arg_it != kw_args.end())
arg_map[i] = given_arg_it->second;
else
arg_map[i] = default_val;
// std::cout << i << " -> " << arg_map[i] << std::endl;
}
return arg_map;
}
// Copies the arguments from the map returned by pre_process_args into a
// std::tuple which can be used with std::apply to call the internal function.
// This uses a faux fold operation because I'm not sure the right way to do a
// fold in more modern C++
// https://articles.emptycrate.com/2016/05/14/folds_in_cpp11_ish.html
template <std::size_t... Index>
std::tuple<ArgTs...>
build_args(std::unordered_map<size_t, std::string> arg_map,
std::index_sequence<Index...>) {
std::tuple<ArgTs...> args;
std::initializer_list<int> _{
(std::get<Index>(args) =
convert_arg<std::tuple_element_t<Index, std::tuple<ArgTs...>>>(
std::move(arg_map[Index])),
0)...};
return args;
}
};
// Factory function to make a command which calls a pointer-to-member
// function. It's important that the reference to the object stays in
// scope as long as the Command object returned!
template <class C, class... ArgTs>
std::unique_ptr<CommandBase> make_command(C &obj,
void (C::*member_function)(ArgTs...),
argument_spec_t argument_spec) {
return std::make_unique<Command<ArgTs...>>(
std::move(argument_spec), [&obj, member_function](ArgTs... args) {
(obj.*member_function)(std::forward<ArgTs>(args)...);
});
}
// Factory function to make a command which calls a std::function.
template <class... ArgTs>
std::unique_ptr<CommandBase>
make_command(std::function<void(ArgTs...)> callable,
argument_spec_t argument_spec) {
return std::make_unique<Command<ArgTs...>>(std::move(argument_spec),
std::move(callable));
}
// Factory function to make a command which calls a free function
template <class... ArgTs>
std::unique_ptr<CommandBase> make_command(void (*fn)(ArgTs...),
argument_spec_t argument_spec) {
return make_command(std::function<void(ArgTs...)>{fn},
std::move(argument_spec));
}
class Action {
public:
void print_two_arguments(int arg1, int arg2) {
std::cout << arg1 << ", " << arg2 << std::endl;
}
void print_one_argument(std::string arg1) { std::cout << arg1 << std::endl; }
};
void print_one_argument_free(std::string arg1) {
std::cout << arg1 << std::endl;
}
int main() {
Action actor;
// my argument specification code splits by string and then extracts
// arguments by position or keyword and replacing with a default if
// not specified
auto command1 = make_command(actor, &Action::print_one_argument,
argument_spec_t{{0, "first_arg", "something"}});
command1->apply("first_arg=hello_world"); // Should print "hello_world"
auto command2 = make_command(
actor, &Action::print_two_arguments,
argument_spec_t{{0, "first_arg", "2"}, {1, "second_arg", "10"}});
command2->apply("0 second_arg=2"); // should print "0 2"*/
auto command3 = make_command(&print_one_argument_free,
argument_spec_t{{0, "first_arg", "something"}});
command3->apply("first_arg=hello_again");
}
I think there are a number of ways to handle this problem, including function pointers with variable arguments, etc. But your fundamental problem is that you're asking one class to understand the internals of another class, which never works out well. I'd argue instead that you should have a parent Actor class that has a function that can be overridden by sub-classes and just passing an instance of the subclass instead. Each subclass may need to take an array of arguments, or even another container type that each subclass knows what it needs from within.
#include <iostream>
using namespace std;
class Data {
public:
std::string strdata;
int intinfo1;
int intinfo2;
};
class ActionBase {
public:
virtual void act(Data d) = 0;
};
class PrintIntinfos : public ActionBase {
public:
virtual void act(Data d) {
std::cout << d.intinfo1 << ", " << d.intinfo2 << std::endl;
}
};
class PrintStrData : public ActionBase {
public:
virtual void act(Data d) {
std::cout << d.strdata << std::endl;
}
};
int main()
{
ActionBase *Action1 = new PrintIntinfos();
Data d = Data();
d.intinfo1 = 42;
d.intinfo2 = -42;
Action1->act(d);
delete Action1;
d.strdata = "hello world";
Action1 = new PrintStrData();
Action1->act(d);
}
What you should actually do requires analysis of what your goals are with respect to base-pointers and containers and your data structure, flow, etc.
In your apply you describe something that really wants the context of the constructor. What if Command was
class Command {
std::function<void(std::string)> callable;
public:
template <typename... Args>
Command(std::function<std::tuple<Args...>(std::string)> argument_spec, std::function<void(Args...)> callable)
: callable([=](std::string args) { std::apply(callable, argument_spec(args)); })
{ }
void apply(std::string args) {
callable(args);
}
};
You would still be able to use your argument specification code to create the argument_spec parameter

C++ Using container as a template type

I am trying to supply the underlying container/data structure for a class via template argument. I'd like to have the underlying container always contain a certain pointer type and I want the maximum amount of variable allowed to be stored to be limited, no matter which container is used.
I managed to make something simple work for std::vector and std::array .
However, for the std::array example there are some weird things I have to do so it compiles.
Here is the test code:
#include <iostream>
#include <type_traits>
#include <vector>
#include <array>
#include <algorithm>
#include <map>
class CustomVariableIF {
public:
void getFoo() const {
std::cout << "Moh!" << std::endl;
return;
}
};
template <typename T>
class CustomVariable: public CustomVariableIF {
public:
CustomVariable(T initValue): value(initValue) {}
void setValue(T newValue) {
value = newValue;
}
T getValue() const {
return value;
}
private:
T value = 0;
};
template <typename TContainer>
class CustomVariableSetBase {
public:
using value_type = typename TContainer::value_type;
/* This allows std::array, std::vector and std::map as underlying container */
static_assert(std::is_same<value_type, CustomVariableIF*>::value or
std::is_same<value_type, std::pair<const uint32_t, CustomVariableIF*>>::value,
"Invalid template type!");
CustomVariableSetBase(const size_t maxFillCount): maxFillCount(maxFillCount) {}
virtual~ CustomVariableSetBase() {};
template<class Q = TContainer>
typename std::enable_if<std::is_same<typename Q::value_type, CustomVariableIF*>::value>::type
callFoos() {
size_t currentIdx = 0;
for (auto& var: container) {
if(var == nullptr) {
return;
}
if(currentIdx < fillCount) {
var->getFoo();
currentIdx++;
}
}
}
/* Used if underlying container is a std::map */
template<class Q = TContainer> typename
std::enable_if<std::is_same<typename Q::value_type,
std::pair<const uint32_t, CustomVariableIF*>>::value>::type
callFoos() {
for (auto& var: container) {
var.second->getFoo();
}
}
protected:
virtual void registerVariable(CustomVariableIF* variable) = 0;
TContainer container;
size_t fillCount = 0;
const size_t maxFillCount;
};
class CustomVariableMap: public CustomVariableSetBase<std::map<uint32_t, CustomVariableIF*>> {
public:
CustomVariableMap(const size_t maxVars): CustomVariableSetBase(maxVars) {};
virtual~ CustomVariableMap() {};
void registerVariable(CustomVariableIF* variable) override {
if(fillCount < maxFillCount) {
container.emplace(idCounter, variable);
lastId = idCounter;
idCounter++;
fillCount++;
}
else {
std::cerr << "CustomVariableMap::registerVariable: Map container is full!" << std::endl;
}
return;
}
uint32_t getIdOfLastAddedVariable() const {
return lastId;
}
private:
uint32_t idCounter = 0;
uint32_t lastId = 0;
};
class CustomVariableSet: public CustomVariableSetBase<std::vector<CustomVariableIF*>> {
public:
CustomVariableSet(const size_t maxVars): CustomVariableSetBase(maxVars) {};
virtual~ CustomVariableSet() {};
void registerVariable(CustomVariableIF* variable) override {
if(fillCount < maxFillCount) {
container.push_back(variable);
fillCount++;
}
else {
std::cerr << "CustomVariableSet::registerVariable: Vector container is full!" <<
std::endl;
}
return;
}
private:
};
template <uint8_t NUM_VARIABLES>
class CustomVariableStaticSet:
public CustomVariableSetBase<std::array<CustomVariableIF*, NUM_VARIABLES>> {
public:
using ArrayBase = std::array<CustomVariableIF*, NUM_VARIABLES>;
CustomVariableStaticSet(): CustomVariableSetBase<ArrayBase>(NUM_VARIABLES) {};
virtual void registerVariable(CustomVariableIF* variable) {
if(this->fillCount < NUM_VARIABLES) {
this->container[this->fillCount] = variable;
this->fillCount++;
}
else {
std::cerr << "CustomVariableStaticSet::registerVariable: Array container is full!" <<
std::endl;
}
}
private:
};
int main() {
using namespace std;
CustomVariableSet testSet(2);
CustomVariableStaticSet<5> testSet2;
CustomVariableMap testSet3(2);
CustomVariable<int> someVar1(5);
testSet.registerVariable(&someVar1);
testSet.registerVariable(&someVar1);
std::cout << "Moh! should be printed twice!" << std::endl;
testSet.callFoos();
testSet2.registerVariable(&someVar1);
testSet2.registerVariable(&someVar1);
std::cout << "Moh! should be printed twice!" << std::endl;
testSet2.callFoos();
testSet3.registerVariable(&someVar1);
testSet3.registerVariable(&someVar1);
std::cout << "Moh! should be printed twice!" << std::endl;
testSet3.callFoos();
std::cout << "Should yield two errors!" << std::endl;
testSet.registerVariable(&someVar1);
testSet2.registerVariable(&someVar1);
testSet3.registerVariable(&someVar1);
}
The class which has std::vector as the underlying container works like I expected.
For the std::array one, I have to write the whole template typename again in the constructor initializer list. I also have to write this-> everytime I try to access a member of the base class.
Can anyone explain to me why I have to do these steps for the class using std::array? Thanks a lot in advance!
Kind Regards
RM
Alright, after some more research I found the more in-depth answer here:
https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members
(Question: Why am I getting errors when my template-derived-class uses a member it inherits from its template-base-class?)
A very useful read in general when working with templates. I also updated my test code to include an implementation for std::map as the underlying container, which was tricky because the value type is actually different than for the other two containers. There are still some nullptr checks and some other things missing to be really clean, but it worked for me and maybe it can help some other people.

How to work around C++ pointer-to-member function limitation

C++ has limited ability to use pointer-to-member functions. I need something that will allow me to dynamically choose a callback member function, in order to use the Visitor pattern of the XMLNode::Accept(XMLVisitor *visitor) method from the TinyXML2 library.
To use XMLNode::Accept(), I must call it with a class which implements the XMLVisitor interface. Hence:
typedef bool (*Callback)(string, string);
class MyVisitor : public tinyxml2::XMLVisitor {
public:
bool VisitExit(const tinyxml2::XMLElement &e) {
callback(e.Name(), e.GetText());
}
Callback callback;
}
This works fine if my caller is NOT an object which wants to use one of its own methods as a callback function (so that it can access class variables). For example, this works:
bool myCallBackFunc(string e, string v) {
cout << "Element " << e << " has value " << v << endl;
return true;
}
int main(...) {
tinyxml2::XMLDocument doc;
doc.LoadFile("somefile.xml");
MyVisitor visit;
visit.callback = myCallBackFunc;
doc.Accept(&visit);
}
However, in my use case, the parsing is done inside a method in a class. I have multiple applications which have similar but unique such classes. I'd like to use only one generic MyVisitor class, rather than have the visitor class have unique knowledge of the internals of each class which will call it.
Thus, it would be convenient if the callback function were a method in each calling class so that I can affect the internal state of the object instantiated from that calling class.
Top level: I have 5 server applications which talk to 5 different trading partners, who all send XML responses, but each is enough different that each server app has a class which is unique to that trading partner. I'm trying to follow good OO and DRY design, and avoid extra classes having unique knowledge while still doing basically the same work.
Here's the class method I want Accept() to call back.
ServiceClass::changeState(string elem, string value) {
// Logic which sets member vars based on element found and its value.
}
Here's the class method which will call Accept() to walk the XML:
ServiceClass::processResponse(string xml) {
// Parse XML and do something only if certain elements present.
tinyxml2::XMLDocument doc;
doc.Parse(xml.c_str(), xml.length());
MyVisitor visit;
visit.callback = &changeState; // ERROR. Does not work.
visit.callback = &ServiceClass::changeState; // ERROR. Does not work.
doc.Accept(&visit);
}
What's a simple way to get what I want? I can imagine more classes with derived classes unique to each situation, but that seems extremely verbose and clumsy.
Note: In the interest of brevity, my sample code above has no error checking, no null checking and may even have minor errors (e.g. treating const char * as a string ;-).
Below is the std::bind(..) example for what you're trying to do in C++11. For earlier C++ versions you could use the boost::bind utilities.
Fix your MyVisitor::VisitExit(...) method to return a boolean, by the way.
The code is converting const char * to std::string. tinyxml2 does not guarantee that the char * arguments from Name() or GetText() are not null. In fact in my experience they will be null at some point. You should guard against this. For the sake of not modifying your example too much I've not protected against this possibility everywhere in the example.
typedef bool(*Callback)(string, string);
using namespace std;
class MyVisitor : public tinyxml2::XMLVisitor {
public:
bool VisitExit(const tinyxml2::XMLElement &e) {
// return callback(e.Name(), e.GetText());
return true;
}
Callback callback;
};
/** Typedef to hopefully save on confusing syntax later */
typedef std::function< bool(const char * element_name, const char * element_text) > visitor_fn;
class MyBoundVisitor : public tinyxml2::XMLVisitor {
public:
MyBoundVisitor(visitor_fn fn) : callback(fn) {}
bool VisitExit(const tinyxml2::XMLElement &e) {
return callback(e.Name() == nullptr ? "\0" : e.Name(), e.GetText() == nullptr ? "\0": e.GetText());
}
visitor_fn callback;
};
bool
myCallBackFunc(string e, string v) {
cout << "Element " << e << " has value " << v << endl;
return true;
}
int
main()
{
tinyxml2::XMLDocument doc;
doc.LoadFile("somefile.xml");
MyVisitor visit;
visit.callback = myCallBackFunc;
doc.Accept(&visit);
visitor_fn fn = myCallBackFunc; // copy your function pointer into the std::function<> type
MyBoundVisitor visit2(fn); // note: declare this outside the Accept(..) , do not use a temporary
doc.Accept(&visit2);
}
So from within the ServiceClass method you'd do:
ServiceClass::processResponse(string xml) {
// Parse XML and do something only if certain elements present.
tinyxml2::XMLDocument doc;
doc.Parse(xml.c_str(), xml.length());
// presuming changeState(const char *, const char *) here
visitor_fn fn = std::bind(&ServiceClass::changeState,this,std::placeholders::_1,std::placeholders::_2);
MyBoundVisitor visit2(fn); // the method pointer is in the fn argument, together with the instance (*this) it is a method for.
doc.Accept(&visit);
}
You can use generics in order to support whichever callback you'd like.
I've tried to mock the classes of the library in order to give you a fully runnable example:
#include <string>
#include <iostream>
#include <functional>
class XmlNode {
public:
XmlNode(const std::string& n, const std::string t) : name(n), txt(t) {}
const std::string& Name() const { return name; }
const std::string& GetText() const { return txt; }
private:
std::string name;
std::string txt;
};
class XMLVisitor {
public:
virtual void VisitExit(const XmlNode& node) = 0;
virtual ~XMLVisitor() {}
};
template<typename T>
class MyVisitor : XMLVisitor {
public:
MyVisitor() {}
void myInnerPrint(const XmlNode& node) {
std::cout << "MyVisitor::myInnerPrint" << std::endl;
std::cout << "node.Name(): " << node.Name() << std::endl;
std::cout << "node.GetText(): " << node.GetText() << std::endl;
}
void SetCallback(T newCallback) {
callback = newCallback;
}
virtual void VisitExit(const XmlNode& node) {
callback(node);
}
T callback;
};
int main() {
XmlNode node("In", "Member");
MyVisitor<std::function<void(const XmlNode&)>> myVisitor;
auto boundCall =
[&myVisitor](const XmlNode& node) -> void {
myVisitor.myInnerPrint(node);
};
myVisitor.SetCallback(boundCall);
myVisitor.VisitExit(node);
return 0;
}
First define a template and a helper function:
namespace detail {
template<typename F>
struct xml_visitor : tinyxml2::XMLVisitor {
xml_visitor(F&& f) : f_(std::move(f)) {}
virtual void VisitExit(const tinyxml2::XMLElement &e) {
f_(e);
}
private:
F f_;
};
}
template<class F>
auto make_xml_visitor(F&& f)
{
return detail::xml_visitor<std::decay_t<F>>(std::forward<F>(f));
}
Then use the helper function to construct a custom visitor from a lambda which captures this:
void ServiceClass::processResponse(std::string xml) {
// Parse XML and do something only if certain elements present.
tinyxml2::XMLDocument doc;
doc.Parse(xml.c_str(), xml.length());
auto visit = make_xml_visitor([this](const auto& elem)
{
this->changeState(elem.Name(), elem.GetText);
});
doc.Accept(std::addressof(visit));
}
The rule is that a function pointer must always accept a void * which is passed in to the module which calls it, and passed back. Or use a lambda which is the same thing with some of the machinery automated for you. (The void * is the "closure").
So
typedef bool (*Callback)(string, string, void *context);
class MyVisitor : public tinyxml2::XMLVisitor {
public:
bool VisitExit(const tinyxml2::XMLElement &e) {
callback(e.Name(), e.GetText(), contextptr);
}
Callback callback;
void *contextptr;
}
bool myCallBackFunc(string e, string v, void *context) {
ServiceClass *service = (ServiceClass *) context;
cout << "Element " << e << " has value " << v << endl;
service->ChangeState(e, v);
return true;
}

Creating a generic conversion function

I have a ResourceManager which takes in classes of type Resource. Resource is a parent class of other classes such as ShaderProgram, Texture, Mesh and even Camera who are completely unrelated to one another.
Suffice it to say, the ResourceManager works. But there is one thing that is very tedious and annoying, and that's when I retrieve the objects from the ResourceManager. Here is the problem:
In order to get an object from ResourceManager you call either of these functions:
static Resource* get(int id);
static Resource* get(const std::string &name);
The first function checks one std::unordered_map by an integer id; whereas the second function checks another std::unordered_map by the name that is manually given by the client. I have two versions of these functions for flexibility sakes because there are times where we don't care what the object contained within ResourceManager is (like Mesh) and there are times where we do care about what it is (like Camera or ShaderProgram) because we may want to retrieve the said objects by name rather than id.
Either way, both functions return a pointer to a Resource. When you call the function, it's as easy as something like:
rm::get("skyboxShader");
Where rm is just a typedef of ResourceManager since the class is static (all members/functions are static). The problem though is that the rm::get(..) function returns a Resource*, and not the child class that was added to the ResourceManager to begin with. So, in order to solve this problem I have to do a manual type conversion so that I can get ShaderProgram* instead of Resource*. I do it like this:
auto s = static_cast<ShaderProgram*>(rm::get(name));
So, everytime I want to access a Resource I have to insert the type I want to actually get into the static_cast. This is problematic insofar that everytime someone needs to access a Resource they have to type convert it. So, naturally I created a function, and being that ShaderProgram is the subject here, thus:
ShaderProgram* Renderer::program(const std::string &name)
{
auto s = static_cast<ShaderProgram*>(rm::get(name));
return s;
}
This function is static, and ResourceManager is a static class so the two go well hand-in-hand. This is a nice helper function and it works effectively and my program renders the result just fine. The problem is what I have to do when I'm dealing with other Resources; that means for every Resource that exists, there has to be a type-conversion function to accommodate it. Now THAT is annoying. Isn't there a way I can write a generic type-conversion function something like this?
auto Renderer::getResource(classTypeYouWant T, const std::string &name)
{
auto s = static_cast<T*>(rm::get(name));
return s;
}
Here, the auto keyword causes the function to derive which type it's supposed to be dealing with and return the result accordingly. My first guess is that I might have to use templates; but the problem with templates is that I can't limit which types get inserted into the function, and I really REALLY don't want floating-point id numbers, char ids, let alone custom-defined ids. It's either string (might change to const char* tbh) or ints or else.
How can I create a generic conversion function like the one described above?
Have you looked at using dynamic_cast? If the conversion fails with dynamic_cast the the pointer will be set to nullptr. So you could either write overloads for each type or you could write a template function where you pass the the type you want to convert to as well as the string or id and if the conversion succeeds or fails return true or false.
template<typename T>
bool Renderer::getResource(T*& type, const std::string &name)
{
type = dynamic_cast<decltype(std::remove_reference<decltype(T)>::type)>(rm::get(name));
if (type == nullptr)
return false;
return true;
}
OK, I did not like the idea of a typeless storage, but maybe you find that basic program as a start point. There are a lot of things which must be beautified, but some work must remain :-)
Again: It is a design failure to solve something in that way!
In addition to your example code this solution provides a minimum of safety while checking for the stored type while recall the element. But this solution needs rtti an this is not available on all platforms.
#include <map>
#include <iostream>
#include <typeinfo>
class ResourcePointerStorage
{
private:
std::map< const std::string, std::pair<void*, const std::type_info*>> storage;
public:
bool Get(const std::string& id, std::pair<void*, const std::type_info*>& ptr )
{
auto it= storage.find( id );
if ( it==storage.end() ) return false;
ptr= it->second;
return true;
}
bool Put( const std::string& id, void* ptr, const std::type_info* ti)
{
storage[id]=make_pair(ptr, ti);
}
};
template < typename T>
bool Get(ResourcePointerStorage& rm, const std::string& id, T** ptr)
{
std::pair<void*, const std::type_info*> p;
if ( rm.Get( id,p ))
{
if ( *p.second != typeid(T)) { return false; }
*ptr= static_cast<T*>(p.first);
return true;
}
else
{
return 0;
}
}
template < typename T>
void Put( ResourcePointerStorage& rm, const std::string& id, T *ptr)
{
rm.Put( id, ptr, &typeid(T) );
}
class Car
{
private:
int i;
public:
Car(int _i):i(_i){}
void Print() { std::cout << "A car " << i << std::endl; }
};
class Animal
{
private:
double d;
public:
Animal( double _d):d(_d) {}
void Show() { std::cout << "An animal " << d << std::endl; }
};
int main()
{
ResourcePointerStorage store;
Put( store, "A1", new Animal(1.1) );
Put( store, "A2", new Animal(2.2) );
Put( store, "C1", new Car(3) );
Animal *an;
Car *car;
if ( Get(store, "A1", &an)) { an->Show(); } else { std::cout << "Error" << std::endl; }
if ( Get(store, "A2", &an)) { an->Show(); } else { std::cout << "Error" << std::endl; }
if ( Get(store, "C1", &car)) { car->Print(); } else { std::cout << "Error" << std::endl; }
// not stored object
if ( Get(store, "XX", &an)) { } else { std::cout << "Expected false condition" << std::endl; }
// false type
if ( Get(store, "A1", &car)) { } else { std::cout << "Expected false condition" << std::endl; }
};
I've found the solution to my question. I created a macro:
#define convert(type, func) dynamic_cast<type>(func)
Extremely generic and code-neutral which allows types to be dynamic_casted from the return type of the function. It also allows for doing checks:
if (!convert(ShaderProgram*, rm::get("skyboxShader")))
cerr << "Conversion unsuccessful!" << endl;
else cout << "Conversion successful!" << endl;
I hope my solution will help people who search for questions similar of this kind. Thanks all!

Boost::signals2 passing invalid data

I've been a C/C++ developer for about 20 years now, but templates have always been a weak spot for me. With template programming becoming ever more useful, and complicated, in the C++11 and C++14 standards, I decided to try an exercise to learn. I've been moderately successful, but I have an issue I'm having problems with. I have the following class:
namespace Events {
// Place your new EventManager events here
static const uint32_t StatsData = 0;
static const uint32_t StatsRequest = 1;
static const uint32_t StatsReply = 2;
static const uint32_t ApplianceStatsRequest = 3;
static const uint32_t ApplianceStatsReply = 4;
static const uint32_t NullEvent = 5;
};
class EventManager {
public:
static EventManager *instance() {
if (Instance)
return Instance;
return new EventManager();
};
static void destroy() {
delete Instance;
Instance = nullptr;
}
template<typename T>
bool consume_event(uint32_t event, std::function<T> func) {
if (_event_map.find(event) == _event_map.end())
// Create the signal, in true RAII style
_event_map[event] = new boost::signals2::signal<T>();
boost::any_cast<boost::signals2::signal<T> *>(_event_map[event])->connect(func);
return true;
}
void emit(uint32_t event) {
if (_event_map.find(event) == _event_map.end())
return;
try {
boost::signals2::signal<void()> *sig =
boost::any_cast<boost::signals2::signal<void()> *>(_event_map[event]);
(*sig)();
}
catch (boost::bad_any_cast &e) {
SYSLOG(ERROR) << "Caught instance of boost::bad_any_cast: " << e.what();
abort();
}
}
template<typename... Args>
void emit(uint32_t event, Args... args) {
if (_event_map.find(event) == _event_map.end())
return;
try {
boost::signals2::signal<void(Args...)> *sig =
boost::any_cast<boost::signals2::signal<void(Args...)> *>(_event_map[event]);
(*sig)(args...);
}
catch (boost::bad_any_cast &e) {
SYSLOG(ERROR) << "Caught instance of boost::bad_any_cast: " << e.what();
abort();
}
}
private:
EventManager() { Instance = this; };
~EventManager() { Instance = nullptr; };
static EventManager *Instance;
std::map<uint32_t, boost::any> _event_map;
};
This code would potentially go into a large framework that loads multiple modules which are dynamic libraries on linux. The idea would be for a given module to be able to call:
consume_event<ParamTypes><EventNumber, SomeCallack)
The callback may be a function with signature void(ParamTypes), or the result of std::bind() on a function with signature void(ParamTypes).
Another module would then be able to call:
emit<ParamTypes>(EventNumber, ParamValues)
and each module that had called consume_event, would have it's handler called with ParamValues.
This seems to work in almost every case, except when I pass a reference to a custom class, like this:
std::cout << "Sending stats data with ref: " << std::hex << ip_entry.second << std::endl;
emit<ip_stats_t &>(Events::StatsData, *ip_entry.second);
In this case, the function that is connected to the signal, receives 0xa, and promptly crashes when it tries to treat it as an ip_stats_t &.
The output is:
Sending stats data with ref: 0x7fbbc4177d50 <- This is the output of the line seen above
ips addr: 0xa << this is from the function that gets called by the signal.
Update: I just noticed it does the same thing when passing any variable by reference, not just the custom class above.
Additionally, please note that there is no SSCCE in this question because any SSCCE invariable works. The problem does not occur until the working code is put into the above framework.
Update2: The real question here is, how can this design be made better. This one not only doesn't work properly, but syntactically, it stinks. it's ugly, inelegant, and really, there's nothing good about it, except that it did what I wanted it to do and increased my understanding of templates.
Update3: I have now 100% confirmed that this has nothing to do with the data type that I'm passing. If I pass any variable by reference, the slot always receives 0xa as the address of the reference. This includes std::strings, and even ints. If I pass any variable by value, the copy constructor of that value eventually receives 0xa as the reference of the value to copy from. This only happens when calling a slot in module B from a signal created in module A. What am I missing?
Any ideas?
Thanks!
UPDATED I've since come up with a demonstration that would appear to be closer to what you were trying to achieve:
#lk75 For fun, here's an approach that abstracts the event mechanism in a fairly extensible way, while
not being overly complicated
not requiring calling signature to be repeated all over the place (it's in Traits now)
not leaking signals by using true RAII style (SCNR). No more use of new or delete!
See it Live On Coliru.
Note how I simplified the singleton and turned both consume_event and emit into one-liners now:
static EventManager& instance() {
static EventManager instance;
return instance;
};
template <EventId event, typename F>
bool consume_event(F&& func) {
get_slot<event>().connect(std::forward<F>(func));
return true;
}
template <EventId event, typename... Args>
void emit(Args&&... args) {
get_slot<event>()(std::forward<Args>(args)...);
}
Full Code
For reference:
Live On Coliru
#include <boost/any.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/signals2/signal.hpp>
#include <iostream>
#include <memory>
#include <string>
struct ip_stats_t {
std::string canary;
};
enum class EventId : uint32_t {
// Place your new EventManager events here
StatsData = 0,
StatsRequest = 1,
StatsReply = 2,
ApplianceStatsRequest = 3,
ApplianceStatsReply = 4,
NullEvent = 5, // Not implemented
};
namespace Events {
template <EventId> struct Traits;
template <> struct Traits<EventId::StatsData> { using signal_type = boost::signals2::signal<void(int)>; } ;
template <> struct Traits<EventId::StatsRequest> { using signal_type = boost::signals2::signal<void(bool, bool)>; } ;
template <> struct Traits<EventId::StatsReply> { using signal_type = boost::signals2::signal<void(std::string)>; } ;
template <> struct Traits<EventId::ApplianceStatsRequest> { using signal_type = boost::signals2::signal<void(double, ip_stats_t&)>; } ;
//template <> struct Traits<EventId::NullEvent> { using signal_type = boost::signals2::signal<void()>; } ;
template <> struct Traits<EventId::ApplianceStatsReply> : Traits<EventId::ApplianceStatsRequest> { };
}
class EventManager {
public:
static EventManager& instance() {
static EventManager instance;
return instance;
};
template <EventId event, typename F>
bool consume_event(F&& func) {
get_slot<event>().connect(std::forward<F>(func));
return true;
}
template <EventId event, typename... Args>
void emit(Args&&... args) {
get_slot<event>()(std::forward<Args>(args)...);
}
private:
template <EventId event, typename Slot = typename Events::Traits<event>::signal_type, typename SlotPtr = boost::shared_ptr<Slot> >
Slot& get_slot() {
try {
if (_event_map.find(event) == _event_map.end())
_event_map.emplace(event, boost::make_shared<Slot>());
return *boost::any_cast<SlotPtr>(_event_map[event]);
}
catch (boost::bad_any_cast const &e) {
std::cerr << "Caught instance of boost::bad_any_cast: " << e.what() << " on event #" << static_cast<uint32_t>(event) << "\n";
abort();
}
}
EventManager() = default;
std::map<EventId, boost::any> _event_map;
};
int main() {
auto& emgr = EventManager::instance();
emgr.consume_event<EventId::ApplianceStatsRequest>([](double d, ip_stats_t& v) {
std::cout << "d: " << d << ", v.canary: " << v.canary << "\n";
});
emgr.consume_event<EventId::ApplianceStatsRequest>([](double d, ip_stats_t& v) {
std::cout << "And you can register more than one\n";
});
ip_stats_t v { "This is statically checked" };
emgr.emit<EventId::ApplianceStatsRequest>(3.142f, v);
emgr.emit<EventId::StatsData>(42); // no connection, but works
emgr.consume_event<EventId::StatsData>([](int) { std::cout << "Now it's connected\n"; });
emgr.emit<EventId::StatsData>(42); // now with connection!
#if 0
emgr.emit<EventId::ApplianceStatsRequest>(); // error: no match for call to ‘(boost::signals2::signal<void(double, ip_stats_t&)>) ()’
emgr.consume_event<EventId::NullEvent>([]{}); // use of incomplete type Traits<NullEvent>
#endif
}
Old answer:
You seem to have trouble with the variadic forwarding:
(*sig)(std::forward<Args>(args)...);
Also, forwarding really makes sense only when taking the arguments by "universal reference":
template<typename... Args>
void emit(uint32_t event, Args&&... args) { // NOTE!!
However, you do not rely on argument type deduction to get the actual value categories (rvalue vs. lvalue). And, rightly so (because the compiler would likely never get the exact argument types "right" to match the stored signal (making the any_cast fail at best, or invoke Undefined Behaviour at best.)
So in this case, you should dispense with the whole forwarding business:
template<typename... Args> using Sig = boost::signals2::signal<void(Args...)>;
template<typename... Args>
void emit(uint32_t event, Args... args) {
if (_event_map.find(event) == _event_map.end())
return;
try {
Sig<Args...> *sig = boost::any_cast<Sig<Args...> *>(_event_map[event]);
(*sig)(args...);
}
catch (boost::bad_any_cast &e) {
std::cerr << "Caught instance of boost::bad_any_cast: " << e.what();
abort();
}
}
Full demo program: Live On Coliru
#include <boost/any.hpp>
#include <boost/signals2/signal.hpp>
#include <iostream>
#include <string>
struct ip_stats_t {
std::string canary;
};
template<typename... Args> using Sig = boost::signals2::signal<void(Args...)>;
std::map<uint32_t, boost::any> _event_map;
template<typename... Args>
void emit(uint32_t event, Args&&... args) {
if (_event_map.find(event) == _event_map.end())
return;
try {
Sig<Args...> *sig = boost::any_cast<Sig<Args...> *>(_event_map[event]);
(*sig)(std::forward<Args>(args)...);
}
catch (boost::bad_any_cast &e) {
std::cerr << "Caught instance of boost::bad_any_cast: " << e.what();
abort();
}
}
int main()
{
Sig<int, double> sig1;
Sig<ip_stats_t&> sig2;
sig1.connect([](int i, double d) { std::cout << "Sig1 handler: i = " << i << ", d = " << d << "\n"; });
sig2.connect([](ip_stats_t& v) { std::cout << "Sig2 handler: canary = " << v.canary << "\n"; });
_event_map[1] = &sig1;
_event_map[2] = &sig2;
emit<int, double>(1, 42, 3.14);
ip_stats_t instance { "Hello world" }, *ptr = &instance;
emit<ip_stats_t&>(2, *ptr);
}
The following code, which is Sehe's revised code without the boost::signals solved my problem completely. It would appear that boost::signals was having issues passing any data whatsoever across module boundries. Replacing it with a simple vector of functions works in all cases, and is faster anyway!
enum class EventId : uint32_t {
// Place your new EventManager events here
StatsData = 0,
StatsRequest = 1,
StatsReply = 2,
ApplianceStatsRequest = 3,
ApplianceStatsReply = 4,
};
struct ip_stats_t;
namespace Events {
template <EventId> struct Traits;
template <> struct Traits<EventId::StatsData>
{ using signal_vec = std::vector<std::function<void(ip_stats_t &)>>; } ;
template <> struct Traits<EventId::StatsRequest>
{ using signal_vec = std::vector<std::function<void(std::ostream &)>>; } ;
template <> struct Traits<EventId::StatsReply>
{ using signal_vec = std::vector<std::function<void(std::string &)>>; } ;
template <> struct Traits<EventId::ApplianceStatsRequest> :
Traits<EventId::StatsRequest> {};
template <> struct Traits<EventId::ApplianceStatsReply> :
Traits<EventId::StatsReply> {};
}
class EventManager {
public:
static EventManager& instance() {
static EventManager instance;
return instance;
};
template <EventId event, typename F>
void consume_event(F&& func) {
get_slot<event>().push_back(std::forward<F>(func));
}
template <EventId event, typename... Args>
void emit(Args&&... args) {
for (auto &vi : get_slot<event>()) {
vi(std::forward<Args>(args)...);
}
}
private:
template <EventId event,
typename Slot = typename Events::Traits<event>::signal_vec,
typename SlotPtr = std::shared_ptr<Slot>>
Slot& get_slot() {
if (_event_map.find(event) == _event_map.end())
_event_map.emplace(event, std::make_shared<Slot>());
try {
return *boost::any_cast<SlotPtr>(_event_map[event]);
}
catch (boost::bad_any_cast const &e) {
std::cerr << e.what() << " on event #" << static_cast<uint32_t>(event) << "\n";
abort();
}
}
EventManager() = default;
std::map<EventId, boost::any> _event_map;
};