I'm trying to add a simple messaging system to my project, where events can be invoked by a function, which will lead to all callbacks registered to that event being called.
Now, the logical way to do this is using function pointers. It would be easily possible to pass the pointer to the desired callback function to the events manager, for registering. An event callback function would always return an int and take a void* as argument.
However I don't want to register static global functions as my event callbacks - I'd like to do it with class member functions.
Is it even possible to accomplish this with C++? Storing and calling pointers to member functions of different classes but with the same function header.
If this is not possible, do you have any suggestions on how I could work around this? I'd really like to add event listeners directly to my classes.
Yes it is possible. C++0x has the function class that handles this, and as others have pointed out Boost has similar facilities.
You can also roll your own, but the syntax is not for the faint of heart:
#include <iostream>
class Callable
{
public:
virtual ~Callable() {}
virtual int operator() (void* args) = 0;
};
class CallableFreeFunction : public Callable
{
public:
CallableFreeFunction(int (*func)(void*)) : func_(func) {}
virtual int operator() (void* args) { return (*func_)(args); }
private:
int (*func_)(void*);
};
template <typename tClass>
class ClassMemberCallable : public Callable
{
public:
ClassMemberCallable(tClass* instance, int (tClass::*memberfunction)(void*)) : instance_(instance), memberfunc_(memberfunction) {}
virtual int operator() (void* args) { return (instance_->*memberfunc_)(args); }
private:
tClass* instance_;
int (tClass::*memberfunc_)(void*);
};
class Foo
{
public:
int derp(void* args)
{
std::cout << args << '\n';
return 2;
}
};
int freefunctionfoo(void* args)
{
std::cout << "free" << args << '\n';
return 2;
}
int main(int argc, char* argv[])
{
Foo myfoo;
Callable* callable = new ClassMemberCallable<Foo>(&myfoo, &Foo::derp);
(*callable)(0);
delete callable;
callable = new CallableFreeFunction(freefunctionfoo);
(*callable)(0);
delete callable;
std::cin.get();
return 0;
}
This demonstrates a way of handling both free functions, and member functions in an opaque way. This is a simple example, and can be made more generic and robust in a number of ways. I'd refer you to these pages for syntax help:
http://www.newty.de/fpt/index.html
http://www.parashift.com/c++-faq-lite/pointers-to-members.html
I'd also recommend looking at this for more ideas:
http://www.codeproject.com/KB/cpp/FastDelegate.aspx
Of course it's possible ! Have a look at Boost.Signal2 and Boost.Bind.
Boost.Signal2 basically implements a signal and slots system which is exactly what you need.
Then, you can use boost::bind which is a generalization of std::bind1st and std::bind2nd to get function object wrappers to basically anything you can think of (in your case, member methods). It's really powerful.
See this official boost tutorial.
Here is my not-so-good attempt for doing a job like that:
First of all you need a base event handler class, well let's call it EvtHandler for now:
class Event; //implement this yourself, it shall contain general but good info about event
class EvtHandler
{
public:
virtual void handleEvent (Event & evt);
};
Then every class that is supposed to handle events in a way, should derive from this class, and they can implement new functions as much as they want as far as they return the same data type (void in this case) and recieve the same paramteres (Event in this case). Like this:
class Foo : public EvtHandler
{
public:
void handleFooEvent (Event & event);
};
Then I implemented message centers for each special event, which had to register listeners and dispatch events when needed:
class ShutdownMessageCenter
{
typedef std::map<EventHandler *, event_func> ListenerMap;
public:
void register (EvtHandler * handler, void(EvtHandler::*memFunc)(Event &)) {
m_lmap[handler] = memFunc;
}
void callListeners () {
Event shutdown_event (EM_SHUTDOWN /*just imagine this can mean something, idk*/);
ListenerMap::iterator itr = m_lmap.begin ();
for (; itr != m_lmap.end(); ++itr) {
EvtHandler * handler = itr->first;
void (EvtHandler::*func)(Event &) = itr->second;
(handler->*func)(shutdown_event);
}
}
private:
ListenerMap m_lmap;
};
Then you could register your EvtHandlers to this particular message center for example!
ShutdownMessageCenter message_center;
EvtHandler * some_handler = new EvtHandler ();
Foo * some_foo = new Foo ();
message_center.register (some_handler, &EvtHandler::handleEvent);
message_center.register (some_foo, static_cast<void (EvtHandler::*)(Event &)>(&Foo::handleFooEvent);
message_center.callListeners ();
But once again this is not good at all, just thought I would share! Sorry for the mess, haha!
I am not completely sure what you want to archive but maybe you should look at Boost Signals2
It is quite helpful if you want to create some sort of Signal/Slot mechanism.
No, it is not possible (unless you do c++/cli with .net).
Now, you can still create static functions, pass them an object as a parameter, and the only thing that they'll do is call your member function on that object. (Actually a cast will be required first).
The closest that I have managed is to register a static member function as the callback. The static member takes the object (this) pointer as an argument in addition to the arguments sent by the event handler and uses this to call the member function.
class myClass{
public:
static void callback(void *arg, void *obj)
{
if (obj)
reinterpret_cast<myClass*>(obj)->cb(arg);
}
private:
void cb(void *arg);
};
Register myClass::callback and this with your handler. You may need to wrap this in the structure that arg references if you are restricted in what can be returned.
I am using lukes answer with SWIG because SWIG does not support all C++11 features... This probably can be improved even further with Parsa Jamshidis approach.
I modified it to cover even more cases (variable amount of arguments and variable return type):
#include <iostream>
template <typename R, typename ...T>
class Callback
{
public:
virtual ~Callback() {}
virtual R operator() (T... args) = 0;
};
template <typename R, typename ...T>
class FreeCallback : public Callback<R, T...>
{
public:
FreeCallback(R(*func)(T...)) : func_(func) {}
virtual R operator() (T... args) { return (*func_)(args...); }
private:
R(*func_)(T...);
};
template <typename tClass, typename R, typename ...T>
class MemberCallback : public Callback<R, T...>
{
public:
MemberCallback(tClass* instance, R (tClass::*memberfunction)(T...)) : instance_(instance), memberfunc_(memberfunction) {}
virtual R operator() (T... args) { return (instance_->*memberfunc_)(args...); }
private:
tClass * instance_;
R (tClass::*memberfunc_)(T...);
};
class foo {
public:
Callback<int, int> *IntCallback;
Callback<int, int, double, double> *IntDoubleDoubleCallback;
};
class blub {
public:
int func1(int i) {
std::cout << "args: " << i << std::endl;
return 1;
}
int func2(int i, double d1, double d2){
std::cout << "args: " << i << " " << d1 << " " << d2 << std::endl;
return 0;
}
};
int freeFunc1(int i) {
std::cout << "args: " << i << std::endl;
return 1;
}
int freeFunc2(int i, double d1, double d2){
std::cout << "args: " << i << " " << d1 << " " << d2 << std::endl;
return 0;
}
int main() {
foo f;
blub b;
f.IntCallback = new MemberCallback<blub, int, int>(&b, &blub::func1);
f.IntDoubleDoubleCallback = new MemberCallback<blub, int, int, double, double>(&b, &blub::func2);
Callback<int, int> *IntFreeCallback = new FreeCallback<int, int>(&freeFunc1);
Callback<int, int, double, double> *IntDoubleDoubleFreeCallback = new FreeCallback<int, int, double, double>(&freeFunc2);
int ret = (*IntFreeCallback)(42);
std::cout << "ret freeFunc1: " << ret << std::endl;
ret = (*IntDoubleDoubleFreeCallback)(42, 3.1415, 2.7182);
std::cout << "ret freeFunc2: " << ret << std::endl;
ret = (*f.IntCallback)(42);
std::cout << "ret func1: " << ret << std::endl;
ret = (*f.IntDoubleDoubleCallback)(42, 3.1415, 2.7182);
std::cout << "ret func2: " << ret << std::endl;
std::cout << "Hello World!\n";
// cleanup not done here...
}
Related
I have this minimal class to represent an event which client can subscribe to.
The event can have an data type associated to it, so when it is triggered by a publisher, an argument of that type would be passed to the client's callback:
template<typename Arg, typename Callback = function<void(const Arg&)>>
class Event
{
public:
Event(Callback c) : mCallback(c){}
void Trigger(const Arg& arg) {
mCallback(arg);
}
private:
Callback mCallback;
};
Now I can create an Event<int> or any other concrete type, but it is really important to me to also allow "empty" event, which has no data associated with it: Event<void>
But sadly that doesn't work:
static void FooVoid() {
cout << "Look ma, no args!" << endl;
}
static void FooInt(int a) {
cout << "int arg " << a << endl;
}
int main()
{
/* Compiles */
Event<int> eInt(&FooInt);
eInt.Trigger(42);
/* Does not compile :(
Event<void> eVoid(&FooVoid);
eVoid.Trigger();
*/
return 0;
}
Is there any way to achieve this desired API? How?
(P.S the solution should work on C++11)
The quickest way of solving this without explicitly specializing for void is to use a parameter pack (added in C++11) for your template argument instead of a single type and using an empty parameter pack instead of void. A parameter pack can homogeneously hold any number of type, including 0 and 1. Then it can be used to generate the right types and member functions. You basically just have to add ... correctly near every use of Arg (link) :
#include <functional>
#include <iostream>
template<typename ... Arg>
class Event
{
public:
using Callback = std::function<void(const Arg&...)>;
Event(Callback c) : mCallback(c){}
void Trigger(const Arg& ... arg) {
mCallback(arg...);
}
private:
Callback mCallback;
};
static void FooVoid() {
std::cout << "Look ma, no args!" << std::endl;
}
static void FooInt(int a) {
std::cout << "int arg " << a << std::endl;
}
int main()
{
/* Compiles */
Event<int> eInt(&FooInt);
eInt.Trigger(42);
Event<> eVoid(&FooVoid);
eVoid.Trigger();
return 0;
}
This has the added benefit that you can use callbacks with more than one argument. If this isn't desirable you can add a static_assert to prevent it :
template<typename ... Arg>
class Event
{
public:
using Callback = std::function<void(const Arg&...)>;
static_assert(sizeof...(Arg) <= 1, "Too many arguments");
Event(Callback c) : mCallback(c){}
void Trigger(const Arg& ... arg) {
mCallback(arg...);
}
private:
Callback mCallback;
};
Notice that this solution requires Event<> instead of Event<void>. You can solve that by adding a short specialization for Event<void> that uses Event<> (link) :
template<>
class Event<void> : public Event<>
{
// Inherit constructors
using Event<>::Event;
};
I'm trying to create a generalized a message handling a my code. Each message is identified by a integer id. Since all message handlers have similar deceleration and I like to handle each message quickly, I use a std::map to connect and find corresponding message handler for specific message ids. Then I call this handler and pass message to it. There are several was to do this and here is an example:
const std::map<int, void(*)(void*)> g_handlers = {
{1, h1},
{2, h2}
};
...
// message
int message_id = 2;
int data = 3;
// handle message
g_handlers[message_id](&data);
But there are few big limitation for this method:
Since there are different messages, we need to generalize them by passing them as void* parameter. In this way, every message handler syntax will be void (*)(void*) and then we will be able to use it as value of map.
There is no type checking for this message. If someone incorrectly add message handler of message id 1 for message id 2, we may not find this bug quickly.
I wanted to try something new, so I was trying to find a way to solve these problems and I have finally reached a working code. Here is the code:
class handler_base {
public:
template <typename U>
void operator()(U* arg) {
run(arg, typeid(U));
}
private:
virtual void run(void* arg, const std::type_info& info) {}
};
template<typename T>
class handler : public handler_base {
public:
using type = T;
handler(void (*f)(T*)) :func(f) {
}
private:
void run(void* arg, const std::type_info& info) {
assert(info.hash_code() == typeid(T).hash_code());
func(static_cast<T*>(arg));
}
void (*func)(T*);
};
int main()
{
// 2 different types of handlers
handler h1(+[](double* v){ std::cout << "double called " << *v << "\n"; });
handler h2(+[](int* v){ std::cout << "int called " << *v << "\n"; });
const std::map<int, handler_base&> myhandler = {
{1, h1},
{2, h2}
};
double d = 1.5;
int i = 3;
myhandler.at(1)(&d);
//myhandler.at(1)(&i); // Error: failed assert due to type check
//myhandler.at(2)(&d); // Error: failed assert due to type check
myhandler.at(2)(&i);
}
Now here are my question:
Is using & as map value valid when map is const? I know it is not when map itself is not const but I wonder if it correct in this case or not.
Is there any way simpler way to do this? providing different callback message handler syntax using same container with type checking?
What do you think about this idea generally? Is it a good idea to add this complexity for type checking and heterogeneous callbacks? I personally always go for this rule of "simplicity is the best" and I normally select first approach (using generalized void(*)(void*) for callback), but I like to know what do you think about it.
I think you can completely skip the base class. You just store the function pointer directly as some function pointer for the round trip conversion. I also made it accept many parameters:
#include <unordered_map>
#include <iostream>
#include <cassert>
struct Handler
{
template <typename T>
Handler(T fn)
: f((void(*)())(fn))
, info(typeid(T))
{
}
template <typename... Args>
void operator()(Args&&... args)
{
using Fn = void(Args...);
assert(info.hash_code() == typeid(Fn*).hash_code());
return ((Fn*)(f))(std::forward<Args>(args)...);
}
void (*f)();
const std::type_info& info;
};
int main()
{
std::unordered_map<int, Handler> cbmap;
cbmap.emplace(1, +[](int a, double b){std::cout << "1" << a << " " << b << "\n";});
cbmap.emplace(2, +[](double a){std::cout << "2" << a << "\n";});
cbmap.emplace(3, +[](double& a){std::cout << "3 " << a << "\n";});
double x = 42.0;
cbmap.at(1)(42,4.2);
cbmap.at(2)(4.2);
cbmap.at(3)(x);
}
thanks in advance for your support.
I'm using C++11 and I want to store public member functions of some classes for later use as callback functions; e.g. I want to store some functions that matches this template: void(classname::*)(void). As far as I know, I have to store their objects too, It's fine. For example:
// PSEUDO CODE
class A {
public:
void myfunc() {}
}myobj;
class B {
public:
void myfunc2() {}
}myobj2;
/* storing */
mystorageclass storage;
storage.push(&myobj, &A::myfunc);
storage.push(&myobj2, &B::myfunc2);
/* call them back */
(storage[0].object->*(storage[0].callback))();
(storage[1].object->*(storage[1].callback))();
Is there any safe and generic way to do that? Actually I've found a way, but I'm not sure how much it's portable across processors or compilers.
//test.cpp - compiled with: g++ test.cpp -o test -std=c++11
#include <iostream>
#include <vector>
class A {
public:
void myfunc() { std::cout << "Test A::myfunc()" << std::endl; }
}myobj;
class B {
public:
void myfunc2() { std::cout << "Test B::myfunc2()" << std::endl; }
}myobj2;
struct Callback {
void* object;
void(* method)(void*);
};
std::vector<Callback> callbackList;
template<typename FunctionPtr>
void add(void* object, FunctionPtr fptr) {
Callback cb;
cb.object = object;
cb.method = (void(*)(void*))(*(void**)(&fptr));
callbackList.push_back(cb);
}
int main() {
//add to list for later use
add(&myobj, &A::myfunc);
add(&myobj2, &B::myfunc2);
//call them back
callbackList[0].method(callbackList[0].object);
callbackList[1].method(callbackList[1].object);
}
And another way to do; I feel this is much more safe:
//test2.cpp - compiled with: g++ test2.cpp -o test2 -std=c++11
#include <iostream>
#include <vector>
class A {
public:
void myfunc() { std::cout << "Test A::myfunc()" << std::endl; }
}myobj;
class B {
public:
void myfunc2() { std::cout << "Test B::myfunc2()" << std::endl; }
}myobj2;
struct Callback {
struct A;
A* object;
void(A::* method)();
void call() {
(object->*method)();
}
};
std::vector<Callback> callbackList;
template<typename FunctionPtr>
void add(void* object, FunctionPtr fptr) {
Callback cb;
cb.object = (Callback::A*)object;
cb.method = (void(Callback::A::*)())(fptr);
callbackList.push_back(cb);
}
int main() {
//add to list for later use
add(&myobj, &A::myfunc);
add(&myobj2, &B::myfunc2);
//call them back
callbackList[0].call();
callbackList[1].call();
}
Does these usages are safe? Or what do you suggest instead of these.
Thanks.
Replace Callback with std::function<void()>.
Replace add with
template<class T, class R, class U>
void add(T* object, R(U::*ptr)()) {
Callback cb = [object, ptr]{ object->ptr(); };
callbackList.push_back(cb);
// or just
// callbackList.push_back([object, ptr]{ object->ptr(); });
}
note that this supports passing in pointers-to-parent member functions, and callbacks that do not return void and discarding the result.
std::function stores a generic "call this later". You pass a type compatible with the return value, and args compatible with what you want to call later, in the template signature argument of std::function<signature>. In this case, <void()>.
Problem with the second version
In the line
cb.method = (void(*)(void*))(*(void**)(&fptr));
you are casting a function pointer to void**. I am not sure that is supported by the standard. My guess is it is not. I know casting a function pointer to void* is not supported by the standard. See Print an address of function in C++, g++/clang++ vs vc++ , who is rght? for details.
And then, you proceed to use:
callbackList[1].method(callbackList[1].object);
This relies on conventions used by a compiler to pass this as the first hidden argument when calling a member function of a class. There is no guarantee that the method is used by all compilers. The standard does not explicitly state that.
Problem with the third/last version
You are using:
cb.object = (Callback::A*)object;
cb.method = (void(Callback::A::*)())(fptr);
regardless of whether the object type is A or B. This is cause for undefined behavior. The standard does not support casting of an object pointer to any old pointer type.
A Cleaner Version
Use a base class for Callback.
struct Callback {
virtual ~Callback() = 0;
virtual void call() = 0;
};
Then, use a class template for the real Callbacks.
template <typename T>
struct RealCallback : public Callback
{
RealCallback(T* obj, void (T::*m)(void)) : object(obj), method(m) {}
virtual void call()
{
(object->*method)();
}
T* object;
void (T::*method)();
};
With this, you won't be able to store a list of Callback objects but you can store a list of shared_ptr<Callback>s.
std::vector<std::shared_ptr<Callback>> callbackList;
Here's a complete program that does not rely on any ugly casts and works perfectly.
//test.cpp - compiled with: g++ test.cpp -o test -std=c++11
#include <iostream>
#include <vector>
#include <memory>
class A {
public:
void myfunc() { std::cout << "Test A::myfunc() on " << this << std::endl; }
}myobj;
class B {
public:
void myfunc2() { std::cout << "Test B::myfunc2() on " << this << std::endl; }
}myobj2;
struct Callback {
virtual void call() = 0;
};
template <typename T>
struct RealCallback : public Callback
{
RealCallback(T* obj, void (T::*m)(void)) : object(obj), method(m) {}
virtual void call()
{
(object->*method)();
}
T* object;
void (T::*method)();
};
std::vector<std::shared_ptr<Callback>> callbackList;
template<typename T>
void add(T* object, void (T::*fptr)()) {
RealCallback<T>* cb = new RealCallback<T>(object, fptr);
callbackList.push_back(std::shared_ptr<Callback>(cb));
}
int main() {
//add to list for later use
add(&myobj, &A::myfunc);
add(&myobj2, &B::myfunc2);
std::cout << "myobj: " << &myobj << std::endl;
std::cout << "myobj2: " << &myobj2 << std::endl;
//call them back
callbackList[0]->call();
callbackList[1]->call();
}
Update, in response to comment by Yakk
I think Yakk's suggestion makes sense. You can remove the classes Callback and RealCallback with
using Callback = std::function<void()>;
std::vector<Callback> callbackList;
Then, add can be simplified to:
template<class T>
void add(T* object, void(T::*ptr)()) {
callbackList.push_back([object, ptr]{ (object->*ptr)();});
}
With those changes, main needs to be slightly updated to:
int main() {
//add to list for later use
add(&myobj, &A::myfunc);
add(&myobj2, &B::myfunc2);
std::cout << "myobj: " << &myobj << std::endl;
std::cout << "myobj2: " << &myobj2 << std::endl;
// Updated. Can't use callbackList[0]->call();
//call them back
callbackList[0]();
callbackList[1]();
}
Try with std::function or std::bindboth of them need to keep the reference to the instance:
#include <string>
#include <iostream>
#include <functional>
using namespace std;
class MyClass
{
int _value;
public:
MyClass(int value)
{
_value = value;
}
void food()
{
cout << "Foo is doing something whit value: " << _value << endl;
}
void bar()
{
cout << "Bar is doing something whit value: " << _value << endl;
}
};
int main()
{
MyClass* c1 = new MyClass(1);
MyClass* c2 = new MyClass(2);
cout << "Using 'std::function':" << endl;
std::function<void(MyClass&)> food = &MyClass::food;
std::function<void(MyClass&)> bar = &MyClass::bar;
food(*c1);
bar(*c1);
food(*c2);
bar(*c2);
cout << "Using 'std::bind':" << endl;
auto foodBind = std::bind(&MyClass::food, std::placeholders::_1);
auto barBind = std::bind(&MyClass::bar, std::placeholders::_1);
foodBind(*c1);
barBind(*c1);
foodBind(*c2);
barBind(*c2);
system("PAUSE");
};
the Output is:
Suppose you have a class Foo with a function Foo::bar().
Surrounding this function is a Monitor<Foo> class, which wrapps around Foo and forwards any function call by overloading operator->.
Further, the Monitor class has a boolean flag execute. If execute is true, all function calls
of Foo should be executed normally, but if execute is set to false, execution should be skipped.
The following snippet shows how this could look like:
#include <iostream>
using namespace std;
class Foo {
void bar() {std::cout << "Foo::bar()";}
};
template<typename T> class Monitor<T> {
T& ref;
bool exec;
public:
Monitor(T& obj) : ref(obj), exec(true) {}
T* operator->() {/* if exec */ return &ref;}
void setExec(bool e) {exec = e;}
};
int main() {
Foo foo;
Monitor<Foo> monitor(foo);
monitor->bar(); // call Foo::bar();
monitor.setExec(false);
monitor->bar(); // do nothing
}
Is this possible to implement? The obvious solution is to have a Base class IFoo, and
a Mock implementation MockFoo doing nothing, and then return a pointer to a MockFoo object
when operator-> is called. This makes the whole thing rather inflexible however, as you have to
provide a Mock object for any class you want to monitor.
So, is there a better way to achieve this?
In case you know which function you are going to call, you could do something like the following. This even allows for specification of a default return value of the function in the case exec==false. I am sure I didn't consider all the possible traps of reference return arguments, const member functions, etc. But I am sure you can adapt it if you want to use it.
#include <iostream>
struct X {
double callX(const int& x){ return x/100.;};
};
struct Y {
int callY(const std::string& y){ return y.length();};
};
template<typename F> class Monitor;
template<typename T, typename Ret, typename ...Args>
class Monitor<Ret(T::*)(Args...)> {
T& ref;
Ret(T::*func)(Args...);
Ret defaultRet;
bool exec;
public:
Monitor(T& ref, Ret(T::*func)(Args...), Ret defaultRet = Ret())
: ref(ref),
func(func),
defaultRet(defaultRet),
exec(true){};
void setExec(bool e) {exec = e;};
Ret call(Args&&... args) {
if(exec)
return (ref.*func)(std::forward<Args>(args)...);
else
return defaultRet;
};
};
template<typename T, typename Ret, typename ...Args>
auto makeMonitor(T& x, Ret(T::*f)(Args...), Ret r = Ret()) {
return Monitor<Ret(T::*)(Args...)>(x,f,r);
}
int main() {
X x;
Y y;
auto xmon = makeMonitor(x, &X::callX);
auto ymon = makeMonitor(y, &Y::callY);
auto ymon_def = makeMonitor(y, &Y::callY, 123);
std::cout << "callX(3)=" << xmon.call(3) << std::endl;
std::cout << "callY(\"hello\")=" << ymon.call("hello") << std::endl;
std::cout << "[default return] callY(\"hello\")=" << ymon_def.call("hello") << std::endl;
xmon.setExec(false);
ymon.setExec(false);
ymon_def.setExec(false);
std::cout << "After setExec(false):" << std::endl;
std::cout << "callX(3)=" << xmon.call(3) << std::endl;
std::cout << "callY(\"hello\")=" << ymon.call("hello") << std::endl;
std::cout << "[default return] callY(\"hello\")=" << ymon_def.call("hello") << std::endl;
return 0;
}
Output is:
callX(3)=0.03
callY("hello")=5
[default return] callY("hello")=5
After setExec(false):
callX(3)=0
callY("hello")=0
[default return] callY("hello")=123
Working example is here.
The "obvious" solution you mentioned can be streamlined a little, so you only have to define one additional (mock) class and no additional base classes. If you don't mind the slight performance loss due to virtual member functions, you can go about it like this:
#include <iostream>
struct MockX;
struct X {
typedef MockX mock;
virtual double doX(int x){ return x/100.;};
};
struct MockX : X {
virtual double doX(int x){ return 0.;};
};
struct MockY;
struct Y {
typedef MockY mock;
virtual int doY(std::string y){ return y.length();};
};
struct MockY : Y {
virtual int doY(std::string y){ return 123;};
};
template <typename T>
struct Monitor {
T& ref;
static typename T::mock dummy;
bool exec;
Monitor(T& ref) : ref(ref), exec(true){};
void setExec(bool e){exec = e;};
T* operator->(){
if(exec)
return &ref;
else
return &dummy;
};
};
template<typename T>
typename T::mock Monitor<T>::dummy{};
int main() {
X x;
Y y;
auto xmon = Monitor<X>(x);
auto ymon = Monitor<Y>(y);
std::cout << "doX(3)=" << xmon->doX(3) << std::endl;
std::cout << "doY(\"hello\")=" << ymon->doY("hello") << std::endl;
xmon.setExec(false);
ymon.setExec(false);
std::cout << "After setExec(false):" << std::endl;
std::cout << "doX(3)=" << xmon->doX(3) << std::endl;
std::cout << "doY(\"hello\")=" << ymon->doY("hello") << std::endl;
return 0;
}
I made the dummy mock object static, so there will only be one copy for each type you're monitoring. Everything you need is a typedef in the real class specifying your mock class, and the mock class inheriting from the real class and overriding the (virtual) methods you want to disable when exec==false. You have to be aware though that even the methods you don't override will be called on the dummy object when exec==false, so they might not behave as expected.
However, this could also be an advantage: If you write X and Y in such a way that a default-constructed object (or one constructed with a special flag specified in the constructor) behaves like a mock class, you don't even need a mock-class (just construct dummy that way). But then you could almost build that "disabling" functionality into X itself and you don't need the monitor... ;-)
Consider the following setup.
Base class:
class Thing {
int f1;
int f2;
Thing(NO_INIT) {}
Thing(int n1 = 0, int n2 = 0): f1(n1),f2(n2) {}
virtual ~Thing() {}
virtual void doAction1() {}
virtual const char* type_name() { return "Thing"; }
}
And derived classes that are different only by implementation of methods above:
class Summator {
Summator(NO_INIT):Thing(NO_INIT) {}
virtual void doAction1() override { f1 += f2; }
virtual const char* type_name() override { return "Summator"; }
}
class Substractor {
Substractor(NO_INIT):Thing(NO_INIT) {}
virtual void doAction1() override { f1 -= f2; }
virtual const char* type_name() override { return "Substractor"; }
}
The task I have requires ability to change class (VTBL in this case) of existing objects on the fly. This is known as dynamic subclassing if I am not mistaken.
So I came up with the following function:
// marker used in inplace CTORs
struct NO_INIT {};
template <typename TO_T>
inline TO_T* turn_thing_to(Thing* p)
{
return ::new(p) TO_T(NO_INIT());
}
that does just that - it uses inplace new to construct one object in place of another. Effectively this just changes vtbl pointer in objects. So this code works as expected:
Thing* thing = new Thing();
cout << thing->type_name() << endl; // "Thing"
turn_thing_to<Summator>(thing);
cout << thing->type_name() << endl; // "Summator"
turn_thing_to<Substractor>(thing);
cout << thing->type_name() << endl; // "Substractor"
The only major problems I have with this approach is that
a) each derived classes shall have special constructors like Thing(NO_INIT) {} that shall do precisely nothing. And b) if I will want to add members like std::string to the Thing they will not work - only types that have NO_INIT constructors by themselves are allowed as members of the Thing.
Question: is there a better solution for such dynamic subclassing that solves 'a' and 'b' problems ? I have a feeling that std::move semantic may help to solve 'b' somehow but not sure.
Here is the ideone of the code.
(Already answered at RSDN http://rsdn.ru/forum/cpp/5437990.1)
There is a tricky way:
struct Base
{
int x, y, z;
Base(int i) : x(i), y(i+i), z(i*i) {}
virtual void whoami() { printf("%p base %d %d %d\n", this, x, y, z); }
};
struct Derived : Base
{
Derived(Base&& b) : Base(b) {}
virtual void whoami() { printf("%p derived %d %d %d\n", this, x, y, z); }
};
int main()
{
Base b(3);
Base* p = &b;
b.whoami();
p->whoami();
assert(sizeof(Base)==sizeof(Derived));
Base t(std::move(b));
Derived* d = new(&b)Derived(std::move(t));
printf("-----\n");
b.whoami(); // the compiler still believes it is Base, and calls Base::whoami
p->whoami(); // here it calls virtual function, that is, Derived::whoami
d->whoami();
};
Of course, it's UB.
For your code, I'm not 100% sure it's valid according to the standard.
I think the usage of the placement new which doesn't initialize any member variables, so to preserve previous class state, is undefined behavior in C++. Imagine there is a debug placement new which will initialize all uninitialized member variable into 0xCC.
union is a better solution in this case. However, it does seem that you are implementing the strategy pattern. If so, please use the strategy pattern, which will make code a lot easier to understand & maintain.
Note: the virtual should be removed when using union.
Adding it is ill-formed as mentioned by Mehrdad, because introducing virtual function doesn't meet standard layout.
example
#include <iostream>
#include <string>
using namespace std;
class Thing {
int a;
public:
Thing(int v = 0): a (v) {}
const char * type_name(){ return "Thing"; }
int value() { return a; }
};
class OtherThing : public Thing {
public:
OtherThing(int v): Thing(v) {}
const char * type_name() { return "Other Thing"; }
};
union Something {
Something(int v) : t(v) {}
Thing t;
OtherThing ot;
};
int main() {
Something sth{42};
std::cout << sth.t.type_name() << "\n";
std::cout << sth.t.value() << "\n";
std::cout << sth.ot.type_name() << "\n";
std::cout << sth.ot.value() << "\n";
return 0;
}
As mentioned in the standard:
In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time. [ Note: One special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence (9.2), and if an object of this standard-layout union type contains one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of standard-layout struct members; see 9.2. — end note ]
Question: is there a better solution for such dynamic subclassing that solves 'a' and 'b' problems ?
If you have fixed set of sub-classes then you may consider using algebraic data type like boost::variant. Store shared data separately and place all varying parts into variant.
Properties of this approach:
naturally works with fixed set of "sub-classes". (though, some kind of type-erased class can be placed into variant and set would become open)
dispatch is done via switch on small integral tag. Sizeof tag can be minimized to one char. If your "sub-classes" are empty - then there will be small additional overhead (depends on alignment), because boost::variant does not perform empty-base-optimization.
"Sub-classes" can have arbitrary internal data. Such data from different "sub-classes" will be placed in one aligned_storage.
You can make bunch of operations with "sub-class" using only one dispatch per batch, while in general case with virtual or indirect calls dispatch will be per-call. Also, calling method from inside "sub-class" will not have indirection, while with virtual calls you should play with final keyword to try to achieve this.
self to base shared data should be passed explicitly.
Ok, here is proof-of-concept:
struct ThingData
{
int f1;
int f2;
};
struct Summator
{
void doAction1(ThingData &self) { self.f1 += self.f2; }
const char* type_name() { return "Summator"; }
};
struct Substractor
{
void doAction1(ThingData &self) { self.f1 -= self.f2; }
const char* type_name() { return "Substractor"; }
};
using Thing = SubVariant<ThingData, Summator, Substractor>;
int main()
{
auto test = [](auto &self, auto &sub)
{
sub.doAction1(self);
cout << sub.type_name() << " " << self.f1 << " " << self.f2 << endl;
};
Thing x = {{5, 7}, Summator{}};
apply(test, x);
x.sub = Substractor{};
apply(test, x);
cout << "size: " << sizeof(x.sub) << endl;
}
Output is:
Summator 12 7
Substractor 5 7
size: 2
LIVE DEMO on Coliru
Full Code (it uses some C++14 features, but can be mechanically converted into C++11):
#define BOOST_VARIANT_MINIMIZE_SIZE
#include <boost/variant.hpp>
#include <type_traits>
#include <functional>
#include <iostream>
#include <utility>
using namespace std;
/****************************************************************/
// Boost.Variant requires result_type:
template<typename T, typename F>
struct ResultType
{
mutable F f;
using result_type = T;
template<typename ...Args> T operator()(Args&& ...args) const
{
return f(forward<Args>(args)...);
}
};
template<typename T, typename F>
auto make_result_type(F &&f)
{
return ResultType<T, typename decay<F>::type>{forward<F>(f)};
}
/****************************************************************/
// Proof-of-Concept
template<typename Base, typename ...Ts>
struct SubVariant
{
Base shared_data;
boost::variant<Ts...> sub;
template<typename Visitor>
friend auto apply(Visitor visitor, SubVariant &operand)
{
using result_type = typename common_type
<
decltype( visitor(shared_data, declval<Ts&>()) )...
>::type;
return boost::apply_visitor(make_result_type<result_type>([&](auto &x)
{
return visitor(operand.shared_data, x);
}), operand.sub);
}
};
/****************************************************************/
// Demo:
struct ThingData
{
int f1;
int f2;
};
struct Summator
{
void doAction1(ThingData &self) { self.f1 += self.f2; }
const char* type_name() { return "Summator"; }
};
struct Substractor
{
void doAction1(ThingData &self) { self.f1 -= self.f2; }
const char* type_name() { return "Substractor"; }
};
using Thing = SubVariant<ThingData, Summator, Substractor>;
int main()
{
auto test = [](auto &self, auto &sub)
{
sub.doAction1(self);
cout << sub.type_name() << " " << self.f1 << " " << self.f2 << endl;
};
Thing x = {{5, 7}, Summator{}};
apply(test, x);
x.sub = Substractor{};
apply(test, x);
cout << "size: " << sizeof(x.sub) << endl;
}
use return new(p) static_cast<TO_T&&>(*p);
Here is a good resource regarding move semantics: What are move semantics?
You simply can't legally "change" the class of an object in C++.
However if you mention why you need this, we might be able to suggest alternatives. I can think of these:
Do v-tables "manually". In other words, each object of a given class should have a pointer to a table of function pointers that describes the behavior of the class. To modify the behavior of this class of objects, you modify the function pointers. Pretty painful, but that's the whole point of v-tables: to abstract this away from you.
Use discriminated unions (variant, etc.) to nest objects of potentially different types inside the same kind of object. I'm not sure if this is the right approach for you though.
Do something implementation-specific. You can probably find the v-table formats online for whatever implementation you're using, but you're stepping into the realm of undefined behavior here so you're playing with fire. And it most likely won't work on another compiler.
You should be able to reuse data by separating it from your Thing class. Something like this:
template <class TData, class TBehaviourBase>
class StateStorageable {
struct StateStorage {
typedef typename std::aligned_storage<sizeof(TData), alignof(TData)>::type DataStorage;
DataStorage data_storage;
typedef typename std::aligned_storage<sizeof(TBehaviourBase), alignof(TBehaviourBase)>::type BehaviourStorage;
BehaviourStorage behaviour_storage;
static constexpr TData *data(TBehaviourBase * behaviour) {
return reinterpret_cast<TData *>(
reinterpret_cast<char *>(behaviour) -
(offsetof(StateStorage, behaviour_storage) -
offsetof(StateStorage, data_storage)));
}
};
public:
template <class ...Args>
static TBehaviourBase * create(Args&&... args) {
auto storage = ::new StateStorage;
::new(&storage->data_storage) TData(std::forward<Args>(args)...);
return ::new(&storage->behaviour_storage) TBehaviourBase;
}
static void destroy(TBehaviourBase * behaviour) {
auto storage = reinterpret_cast<StateStorage *>(
reinterpret_cast<char *>(behaviour) -
offsetof(StateStorage, behaviour_storage));
::delete storage;
}
protected:
StateStorageable() = default;
inline TData *data() {
return StateStorage::data(static_cast<TBehaviourBase *>(this));
}
};
struct Data {
int a;
};
class Thing : public StateStorageable<Data, Thing> {
public:
virtual const char * type_name(){ return "Thing"; }
virtual int value() { return data()->a; }
};
Data is guaranteed to be leaved intact when you change Thing to other type and offsets should be calculated at compile-time so performance shouldn't be affected.
With a propert set of static_assert's you should be able to ensure that all offsets are correct and there is enough storage for holding your types. Now you only need to change the way you create and destroy your Things.
int main() {
Thing * thing = Thing::create(Data{42});
std::cout << thing->type_name() << "\n";
std::cout << thing->value() << "\n";
turn_thing_to<OtherThing>(thing);
std::cout << thing->type_name() << "\n";
std::cout << thing->value() << "\n";
Thing::destroy(thing);
return 0;
}
There is still UB because of not reassigning thing which can be fixed by using result of turn_thing_to
int main() {
...
thing = turn_thing_to<OtherThing>(thing);
...
}
Here is one more solution
While it slightly less optimal (uses intermediate storage and CPU cycles to invoke moving ctors) it does not change semantic of original task.
#include <iostream>
#include <string>
#include <memory>
using namespace std;
struct A
{
int x;
std::string y;
A(int x, std::string y) : x(x), y(y) {}
A(A&& a) : x(std::move(a.x)), y(std::move(a.y)) {}
virtual const char* who() const { return "A"; }
void show() const { std::cout << (void const*)this << " " << who() << " " << x << " [" << y << "]" << std::endl; }
};
struct B : A
{
virtual const char* who() const { return "B"; }
B(A&& a) : A(std::move(a)) {}
};
template<class TO_T>
inline TO_T* turn_A_to(A* a) {
A temp(std::move(*a));
a->~A();
return new(a) B(std::move(temp));
}
int main()
{
A* pa = new A(123, "text");
pa->show(); // 0xbfbefa58 A 123 [text]
turn_A_to<B>(pa);
pa->show(); // 0xbfbefa58 B 123 [text]
}
and its ideone.
The solution is derived from idea expressed by Nickolay Merkin below.
But he suspect UB somewhere in turn_A_to<>().
I have the same problem, and while I'm not using it, one solution I thought of is to have a single class and make the methods switches based on a "item type" number in the class. Changing type is as easy as changing the type number.
class OneClass {
int iType;
const char* Wears() {
switch ( iType ) {
case ClarkKent:
return "glasses";
case Superman:
return "cape";
}
}
}
:
:
OneClass person;
person.iType = ClarkKent;
printf( "now wearing %s\n", person.Wears() );
person.iType = Superman;
printf( "now wearing %s\n", person.Wears() );