I've checked someone's code through a tool, and it said that there is a problem here:
policyCallback = callback;
I cannot find the problem since I'm a beginner.
Could you give me a hint or guide to translate it?
The entire code is below.
std::function <void (std::vector<std::string> resources)> policyCallback;
namepace nsp {
class Manager {
public:
Manager(const std::string &str);
virtual ~Manager();
template <typename FuncType>
void registerPolicyActionCallback(FuncType callback) {
policyCallback = callback;
}
};
} //namespace nsp
namespace nsp{
class Manager;
}
class SomeAPIs {
public:
void policyActionCallback(std::vector<std::string> param);
};
int main() {
nsp::Manager *rManager;
rManager->registerPolicyActionCallback(std::bind(&SomeAPIs::policyActionCallback, this, std::placeholders::_1));
}
Besides some obvious errors in the code, the main problem preventing you from achieving what you want is the way in which you are calling std::bind.
Firstly, your code declares policyActionCallback(/*...*/) private in SomeAPIs. Now while you can call any member function via a pointer to it, regardless of it being public, protected, or private, only members and friends can create a pointer to a private member function. So unless you call std:bind from within the API itself, or a friend of the API, you will only be able to bind to public member functions of the API. For the sake of demonstrating a working concept, I will assume that the functions you want to use for callback are all public members of the API.
Secondly, to bind a member function using std::bind, you need to provide a reference to the function (which you did), as well a reference (or pointer) to an instance of the class to which the member belongs, which you have not done.
Therefore, since the function you want to bind to is a member of SomeAPIs, you need to give a reference to an instance of SomeAPIs. I'm assuming that you intended this to be a pointer to the nsp::Manager instance, which, as I have just explained, is the wrong object to provide a reference to.
Additionally, your use of the this keyword is incorrect. Taken from cppreference, this can appear in the following contexts
Within the body of any non-static member function, including
member initializer list
Within the declaration of a non-static
member function anywhere after the (optional) cv-qualifier sequence,
including dynamic exception specification(deprecated), noexcept
specification(C++11), and the trailing return type(since C++11)
Within default member initializer (since C++11)
Since your use of this fits non of the above, the compiler gives:
error: invalid use of 'this' in non-member function
Here is working code for what you are wanting to achieve. Note how std::bind is now used. (I have added a constructor for Manager, removed the virtual destructor since manager does not have any virtual function, made the function in SomeAPIs public so that std::bind can receive a pointer to it, and deleted the nsp::Manager pointer which now is declared on the free store):
#include <vector>
#include <iostream>
#include <functional>
std::function <void (std::vector<std::string> resources)> policyCallback;
namespace nsp {
class Manager {
public:
Manager() {};
Manager(const std::string &str) {}
// Don't know why this is virtual when this isn't a base class?
// virtual ~Manager();
template <typename FuncType>
void registerPolicyActionCallback(const FuncType callback) {
policyCallback = callback;
}
};
} //namespace nsp
class SomeAPIs {
public:
void policyActionCallback(std::vector<std::string> param) {
for (const auto& p : param) {
std::cout << "SomeAPIs : " << p << "\n";
}
}
};
// Another API for illustration
class SomeOtherAPI {
public:
void policyActionCallback(std::vector<std::string> param) {
for (const auto& p : param) {
std::cout << "SomeOtherAPI : " << p << "\n";
}
}
};
int main() {
// Sample resource vector for demonstration
std::vector<std::string> resources = {"one", "two", "three"};
// Gets rid of uninitialization error -- alternatively declare on stack
nsp::Manager* rManager = new nsp::Manager;
// You need instances of an object to bind to member functions
SomeAPIs api1;
SomeOtherAPI api2;
// Use the first APIs function as callback
rManager->registerPolicyActionCallback(std::bind(&SomeAPIs::policyActionCallback, &api1, std::placeholders::_1));
policyCallback(resources);
// Use the second APIs function as callback
rManager->registerPolicyActionCallback(std::bind(&SomeOtherAPI::policyActionCallback, &api2, std::placeholders::_1));
policyCallback(resources);
delete rManager;
}
Here is a live demo.
The snippet you provided is badly extracted copy. It confuses because the line resourceManager->registerUMSPolicyActionCallback(std::bind(&SomeAPIs::policyActionCallback, this, std::placeholders::_1)); has argument value this, it means it was called inside of a class. There should be pointer to instance of SomeAPIs.
What i meant in the comment is declaration of method registerPolicyActionCallback. It is not necessary to be a template when policyCallback cannot be anything but the only type std::function <void (std::vector<std::string> resources)>;
Anyway all the code looks good. You wrote you used tool to check code, what tool? Does it supports C++11 properly?
Related
I'd like to have child classes register callbacks to their parent class so that users of the parent class can call methods of the child with a known function signature.
typedef int(*Func)(int);
class A
{
public:
void registerFunc(Func f)
{}
};
class B : public A
{
public:
B()
{
A::registerFunc(&B::myF);
}
int myF(int x) {
// do stuff with member variables
return 3;
}
};
But I get this compiler error
main.cpp:18:23: error: cannot initialize a parameter of type 'Func' (aka 'int (*)(int)') with an rvalue of type 'int (B::*)(int)'
A::registerFunc(&B::myF);
^~~~~~~
main.cpp:8:28: note: passing argument to parameter 'f' here
void registerFunc(Func f)
Here's a Repl illustrating the error in a concise example.
https://replit.com/#Carpetfizz/RudeSmoothComments#main.cpp
The accepted answer in a related thread suggested to override a virtual function declared in A but my use case actually requires dynamic callback registrations.
You can try this.
typedef std::function<int (int)> Func;
class A
{
public:
void registerFunc(Func f)
{}
};
class B : public A
{
public:
B()
{
A::registerFunc(std::bind(&B::myF, *this, std::placeholders::_1));
}
int myF(int x) {
// do stuff with member variables
return 3;
}
};
If I understand the goal (and believe me, that's a sketchy 'if'), you want to specify some member of some A derivation to invoke from some A member as a dispatched 'callback' mechanic. If that is the case, then to answer your question in comment, yes, a function and bind can do this. It can even be semi-protected with a little help from sfinae:
Example
#include <iostream>
#include <type_traits>
#include <functional>
#include <memory>
struct A
{
virtual ~A() = default;
std::function<void(int)> callback = [](int){};
template<class Derived>
std::enable_if_t<std::is_base_of<A, Derived>::value>
registerCallback(void (Derived::*pfn)(int))
{
using namespace std::placeholders;
callback = std::bind(pfn, dynamic_cast<Derived*>(this), _1);
}
void fire(int arg)
{
callback(arg);
}
};
struct B : public A
{
void memberfn(int arg)
{
std::cout << __PRETTY_FUNCTION__ << ':' << arg << '\n';
}
};
struct Foo
{
void memberfn(int arg)
{
std::cout << __PRETTY_FUNCTION__ << ':' << arg << '\n';
}
};
int main()
{
std::unique_ptr<A> ptr = std::make_unique<B>();
ptr->registerCallback(&B::memberfn);
// ptr->registerCallback(&Foo::memberfn); // WILL NOT WORK
ptr->fire(42);
}
Output
void B::memberfn(int):42
The Parts
The first part is straight forward. We declare a member variable callback to be a std::function<void(int)> instance. This is where we'll eventually bind our callable object point. The default value is a lambda that does nothing.
The second part is... a little more complicated:
template<class Derived>
std::enable_if_t<std::is_base_of<A, Derived>::value>
registerCallback(void (Derived::*pfn)(int))
This declares registerCallback as an available member function that accepts a non-static member function pointer taking one int as an argument, but only if the class hosting that member function, or a derivative therein, is a derivation of A (or A itself). Some non-A derivative Foo with a member void foo(int) will not compile.
Next, the setup to the callback itself.
using namespace std::placeholders;
callback = std::bind(pfn, dymamic_cast<Derived*>(this), _1);
This just binds the pointer-to-member to this dynamic-cast to the derivation type (which had better work or we're in trouble, see final warning at the end of this diatribe), and sets the call-time placeholder. The _1 you see comes from the std::placeholders namespace, and is used to delay providing an argument to the callback until such time as we actually invoke it (where it will be required,and you'll see that later). See std::placehholders for more information.
Finally, the fire member, which does this:
void fire(int arg)
{
callback(arg);
}
This invokes the registered function object with the provided argument. Both the member function and this are already wired into the object. The argument arg is used to fill in the placeholder we mentioned earlier.
The test driver for this is straightforward:
int main()
{
std::unique_ptr<A> ptr = std::make_unique<B>();
ptr->registerCallback(&B::memberfn);
// ptr->registerCallback(&Foo::memberfn); // WILL NOT WORK
ptr->fire(42);
}
This creates a new B, hosting it in a dynamic A pointer (so you know there is no funny business going on). Even with that, because B derived from A the registerCallback sfinae filtering passes inspection and the callback is registered successfully. We then invoke the fire method, passing our int argument 42, which will be sent to the callback, etc.
Warning: With great power comes great responsibility
Even those there is protection from passing non-A derived member functions, there is absolutely none from the casting itself. It would be trivial to craft a basic A, pass a B member (which will work since A is its base), but there is no B actually present.
You can catch this at runtime via that dynamic_cast, which we're currently not error checking. For example:
registerCallback(void (Derived::*pfn)(int))
{
using namespace std::placeholders;
Derived *p = dynamic_cast<Derived*>(this);
if (p)
callback = std::bind(pfn, p, _1);
}
You can choose the road more risky. Personally, i'd detect the null case and throw an exception just to be safe(er)
I'm currently working on a piece of code in C++11:
class A {
public:
//.. generic public methods which call updateInternalState from time to time ..
private:
void updateInternalState();
B internalState;
};
Now I want to have several versions of class A which are all identical except for the updateInternalState() method, which is to vary and has atleast 3 different versions, doing different things and might have even more in the future. This sounds almost like a good place to use inheritance with a base class, but I'm wondering if there is a template-metaprogramming version for this, e.g.:
#include <functional>
template <std::function<void()> updateInternalState>
class A {
public:
//.. generic public methods, which call updateInternalState from time to time ..
private:
B internalState;
Then I would only have to define the functions somewhere else and explicitly instantiate the versions of A that I want.
I think the biggest problem is that the updateInternalState function needs access to the private members of A. I'm thinking this could be solved by declaring it as a friend of A, or by storing a member of type std::function and assigning the the template argument to it.
Does anyone have experience with such approaches and any recommendations?
Is it a terrible idea and should I just go back to inheritance (which I do not really want, since the rest of the project is written in the generic programming paradigm.)
If update function only uses internalState, you can simply store std::function<void(B&)> as a member, which is passed during construction:
class A
{
public:
template <typename F>
A(F&& func)
: updateFunc(std::forward<F>(func))
void doSomething()
{
updateFunc(internalState);
}
private:
using UpdateFunc = std::function<void(B&)>;
B internalState;
UpdateFunc updateFunc;
};
With this method, you can achieve nice flexibility while still maintaining single type instead of whole hierarchy.
Template-based solution may not be a good idea here - you only need to customize a single function, but making this a class template will cause to generate the whole class for every different function used as an argument. The only advantage is that you can specialize (or partially specialize) the logic, but it sounds like you doesn't need that.
Use inheritance or store update function as a member.
That will be a full academic answer :-)
First remark: What you want to do simply makes no sense!
Step by step:
You can use function pointers as template parameters as this:
using FUNCPTR_T = void(*)();
template < FUNCPTR_T f >
class A {
public:
void DoSomething()
{
(*f)();
}
};
void f1() { std::cout << "f1" << std::endl; }
void f2() { std::cout << "f2" << std::endl; }
int main()
{
A<f1> a1;
A<f2> a2;
a1.DoSomething();
a2.DoSomething();
}
But if you want to pass a parameter to your function, which is a class pointer ( this ), you need to define a function pointer which represents this like:
using FUNCPTR_T = void(*)(!!!POINTER_TO_THE_CLASS!!!);
But this class itself is a template which takes a pointer to a function which has a parameter which is a pointer to a class which takes a pointer to a function .... // endless recursion!
So your attempt simply fail at the point as you are unable to give a correct type for the template parameter.
And as already mentioned: Inheritance is much easier and works perfect. Using CRTP is often used to get access to the using class. Using std::function is much easier but moves the cost to runtime.
You can store a std::function and use lambdas: check out this simple class and its use as an example:
#include <functional>
#include <iostream>
#include <conio.h> // for _getch()
class A {
private:
int _state;
std::function<int()> _updater;
public:
A() : _state( 0 ) {}
void addUpdater( std::function<int()> updater ) {
_updater = updater;
}
void callUpdater() {
updateInternalState();
}
int returnState() const {
return _state;
}
private:
void updateInternalState() {
_state = _updater();
}
};
int main() {
A a;
a.addUpdater( []() { return 5; } );
a.callUpdater();
std::cout << a.returnState() << std::endl;
a.addUpdater( []() { return 10; } );
a.callUpdater();
std::cout << a.returnState() << std::endl;
_getch();
return 0;
}
Then to keep track of different instances of the same class, instead of inheritance you can use a map <id, this*> where id could be an int or a string. Makes for easy look up too. I think this might be better than templates in this situation because if you template this class where only the function differs it will generate a whole new class for each function change. Yes it does move things to runtime because of std::function, but it appears to be simpler to implement and manage.
I am working on game engine as a project during the summer. Every scriptable component should have access to some methods in the scene which they are in. To make this possible i pass lambdas from the scene that calls the respective methods to the scriptable where they are implicitly converted to std::function types.
Scene.h:
class Scene
{
private:
unsigned int _currentId;
std::vector<System*> _systems;
//SCRIPTABLE NEEDS THE BELOW METHODS THESE EXCLUSIVELY:
bool exists(unsigned id);
void destroy(unsigned int);
void addComponent(Component*, unsigned int);
template<typename T> T& getComponent(unsigned int);
template<typename T> bool hasComponent(unsigned int);
template<typename T> void removeComponent(unsigned int);
protected:
unsigned int instantiate(std::vector<Component*>);
public:
Scene(ChangeSceneCallback);
~Scene();
void initiate();
void update(long dt);
};
template<typename T>
inline T & Scene::getComponent(unsigned int id)
{
for (System* system : _systems) {
if (system->corresponds(T)) {
return static_cast<T*>(system->getComponent(entityId));
}
}
}
template<typename T>
inline bool Scene::hasComponent(unsigned int id)
{
for (System* system : _systems) {
if (system->corresponds(T)) {
return system->contains(id);
}
}
}
template<typename T>
inline void Scene::removeComponent(unsigned int id)
{
for (System* system : _systems) {
if (system->corresponds(T)) {
return system->destroy(id);
}
}
}
The callback method works for the non-template functions i need access to, but not the templated ones, so it's out of the question.
Scriptable:
typedef std::function<void(int)> ChangeSceneCallback;
typedef std::function<int(std::vector<Component*>)> InstantiateCallback;
typedef std::function<void(int)> DestroyCallback;
typedef std::function<bool(int)> ExistCallback;
typedef std::function<void(Component*, unsigned int)> AddComponentCallback;
class Scriptable: public Component
{
protected:
ChangeSceneCallback changeScene;
InstantiateCallback instantiate;
DestroyCallback destroy;
ExistCallback exists;
public:
~Scriptable();
Scriptable();
void assignCallbacks(ChangeSceneCallback, InstantiateCallback etc ...);
virtual void init() = 0;
virtual void update() = 0;
};
Scriptable can't have access to public methods in scene because this would give the user / developer access to them (Scriptable is a base class for the behaviour of the game). That is why i need to come up with something that gives scriptable limited access to scene.
Any thoughts?
You cannot have a type erased "template callback". You have to choose between the template or the type erasure. Let me explain.
This is what a "template callback" look like. This is in fact a generic lambda:
auto print_callback = [](auto var) {
std::cout << var << std::endl;
}
print_callback(4) ; // prints "4"
print_callback(4.5); // prints "4.5"
print_callback("hello"); // prints "hello"
It seems good but notice that you can't do that with std::function, since you have to predefine the signature.
std::function<void(int)> func_print_callback = print_callback;
func_print_callback(5); // Yay! Prints "5"
func_print_callback("hello"); // error
The thing is, you might think the limitation is only because std::function need a specific signature to work with, but the limitation is much deeper than that.
The thing is, the is no template function. They don't exists. Function template on the other hand, do exist. Why I emphasize so much on the order of my words is because the name of this thing says it all: it is not a function, it a template that is used to make functions.
Here's a simple example:
template<typename T>
void foo(T t) {
std::cout << t << std::endl;
}
This function is not compiled. Because it's not a function. No function foo will exist until the hole T has been filled.
How do you fill the hole named T supposed to be a type?
By filling it with a type of course!
foo(5.4); // the hole T is `double`
When the compiler sees this, it knows you need a function named foo that takes a double as parameter. There is no function named foo that takes a double. But we gave the compiler a tool to create one: the template!
So the compiler will generate this function:
void foo_double(double t) {
std::cout << t std::endl;
}
The word here is this: generate. The compiler need to create the function in order to exist. The compiler generate code for you.
When the function is generated and compiled, T do not exist anymore. A template parameter is a compile-time entity, and only the compiler knows about them.
Now, I'll explain to you why there is no such thing as a template callback.
Type erased container such as std::function are implemented with pointer to function. I'll use type aliases to ease the syntax a bit. It works like this:
// A function
void foo(int) {}
// The type of the pointer to function
using func_ptr = void(*)(int);
// A pointer to foo
func_ptr ptr = &foo;
The pointer to the function foo has a value that points to the location of foo in the memory.
Now imagine we have a way to have template function pointer. We would have to point to a function that does not exist yet. It has no memory location, so it cannot make sense. And through the pointer, when invoked as a function, you'd have to generate the function code.
Since a pointer to function can point to any function, even functions that aren't known to the compiler yet, you'd have to somehow generate the function code and compile it. But the value of the pointer, to which function our pointer points to, is defined at runtime! So you'd have to compile code at runtime, for code that you don't know yet, from a value that does not exist, when the compiler don't exist anymore. As you can see, pointer to template function, template std::function or virtual template function cannot exist.
Now that you have understood the problem, let me propose a solution: drop the callback usage. You should call those functions directly.
You seem to use callback only to be able to call private member functions. This is the wrong way to do it, even if it works. What you need is friend, the feature of C++ that allows you to access private members.
class Scene {
friend Component;
// ...
};
class Component {
protected:
// Let `scene` be a reference to your scene
void addComponent(Component* c, unsigned int id) {
scene.addComponent(c, id);
}
template<typename T>
T& getComponent(unsigned int id) {
return scene.getComponent<T>(id);
}
template<typename T>
bool hasComponent(unsigned int id) {
return scene.hasComponent(id);
}
template<typename T>
void removeComponent(unsigned int id) {
removeComponent(id);
}
// ...
};
Since the Component class is the only friend to Scene, only it can call private member functions. Since all those newly defined functions in Component are protected, only class that extends from Component can call those. They are invoked like this:
class Scriptable : public Component {
void foo() {
hasComponent<Bar>(87); // works, call function defined in `Component`
}
};
I will describe my problem the simplest as I can.
What is my issue:
I have frist class as a singleton:
class CTimer1
{
public:
static CTimer1 * getInstance(); //This gives me pointer to instance
void setChannelA(uint8_t compareValue);
private:
//Cnstructors
CTimer1(); //Prevent consttuction but allow in getInstance
CTimer1(const CTimer1&); //Prevent construction by copying
CTimer1& operator=(const CTimer1&); //Prevent assigment
~CTimer1(); //Prevent unwanted destruction
static CTimer1 * timerInstance;
static bool isCreated;
};
And here is second class where I would like to have possibility to call setChannelA method from CTimer1 class as a setPwm method from CServo class:
class CServo {
public:
CServo();
~CServo();
public:
//public methods
void registerPwmTimer(void (*callback)(uint8_t u8_buffer));
void (*setPwm)(uint8_t u8_buffer); //As this method I would like to call setChannelA from CTimer1 class
};
Here is registerPwmTimer method:
void CServo::registerPwmTimer(void (*callback)(uint8_t u8_buffer))
{
setPwm = callback;
}
Then I have tried to assign pointer to this method as a following:
int main()
{
CTimer1 * timer1 = CTimer1::getInstance();
CServo servo1();
servo1.registerPwmTimer(timer1->setChannelA);
servo1.setPwm(10); //This is example how I want to call setChannelA method
while(1)
{
}
}
I have error:
error: no matching function for call to 'CServo::registerPwmTimer(<unresolved overloaded function type>)'
What is important:
I can't use std::function because this is some part of code in C++ for embedded device, so I need to save memory consumption. Is there any way that I will be able to achieve this effect? If ony one possibility to do this is ot use some std library please for answers too. Thanks for your help.
Your problem is that a function pointer necessarily has to point to a static function. When you invoke an instance function (a method) there is a hidden first argument, which is the object on which the function was invoked. (This hidden argument is available as this within the function's definition.)
Your CServo::registerPwmTimer() function signature is simply incompatible with invocation of a member function; function pointers alone do not provide a way to bind an argument to the pointer, so even if you could convey the member function pointer using a (free) function pointer type, the hidden this argument could not be determined when the function pointer was invoked.
To put it another way, it would fail for the same reason that trying CTimer1::setChannelA(0) would fail -- you want to invoke that method, but you haven't communicated which object on which to invoke it.
Change the signature of CServo::registerPwmTimer to accept an std::function object instead of a raw function pointer. std::function objects can be constructed from function pointers, but they can also be constructed from lambdas, and some standard library functions return function objects:
void registerPwmTimer(std::function<void(uint8_t)>);
Now, you can use std::bind to create a new function that binds the object instance to the member function pointer:
servo1.registerPwmTimer(std::bind(&CTimer1::setChannelA, timer1));
Note that std::bind does not extend the lifetime of the object pointed to by timer1. If the returned function is invoked after that object is destructed, the result is undefined behavior.
Another alternative would be to accept both an instance and a pointer to a member function. The problem with this approach is it requires using templates:
template <typename T>
void registerPwmTimer(void (T::*)(uint8_t), T&);
This isn't bad in itself, but what you'll wind up doing is creating a polymorphic wrapper class so that you can insert this into your callback list alongside other callbacks that don't share the same T. At that point, you're just recreating std::function, since std::function already serves the purpose of being a polymorphic wrapper around callable things.
To illustrate the mess of implementing a polymorphic callable wrapper yourself, here is a very light example. I will show the declarations of a set of these types, and link to an example implementation.
This is the base type, with a pure virtual operator() that serves as the invocation operation.
class poly_callable
{
public:
virtual void operator()(int) const = 0;
};
Now we have a type for function pointers (also works with pointer-to-functor):
template <typename T>
class fn_poly_callable : public poly_callable
{
public:
typedef T fn_type;
fn_poly_callable(T);
virtual void operator()(int) const;
private:
T fn;
};
And one for member functions -- oh, but const member functions and non-const member functions are not interchangeable, so we need an extra template parameter for that:
template <typename T, typename M = void (T::*)(int)>
class member_poly_callable : public poly_callable
{
public:
typedef T object_type;
typedef M member_fn_type;
member_poly_callable(member_fn_type, object_type&);
virtual void operator()(int) const;
private:
member_fn_type mfn;
object_type& target;
};
Plus we'll want some helper functions to allow the compiler to infer the template types. One for function pointers:
template <typename T>
std::unique_ptr<poly_callable> make_poly_callable(T fn)
{
return std::unique_ptr<poly_callable>(new fn_poly_callable<T>(fn));
}
Two for member functions (const and non-const):
template <typename T>
std::unique_ptr<poly_callable> make_poly_callable(void (T::*mfn)(int), T& target)
{
return std::unique_ptr<poly_callable>(new member_poly_callable<T>(mfn, target));
}
template <typename T>
std::unique_ptr<poly_callable> make_poly_callable(void (T::*mfn)(int) const, T& target)
{
return std::unique_ptr<poly_callable>(new member_poly_callable<T, void (T::*)(int) const>(mfn, target));
}
If you want to see it all in action, I made a "simple" and working example.
So... just use std::function. There's no reason to reinvent this stuff.
Suppose we have an abstract Base class that is inherited:
class Base
{
protected:
Base() {}
virtual ~Base() {}
virtual void on_event_foo(int) {}
virtual void on_event_bar(int) {}
};
struct Concrete : public Base
{
virtual void on_event_foo(int value) {/*do some stuff with #value*/}
};
Is it a way to know (at compile time would be the best) the virtual functions from Base that was overridden (with some code in constructor, or with a special pattern)?
My purpose is to implement a wrapper for a library that use some callbacks ; and if I can do check the overriden functions, I will create only the callbacks the user wants.
I want the user can choose the function he wants to override. Then in my code, I will create callbacks only for the overridden functions. The pure virtual functions are not a solution, because they cannot permit to create a concrete class without overriding all of them.
In the constructor of Base, for now, I connect a lot of static callback functions of Base within a C API. In those functions, I call the corresponding member function. For example, the callback function is static Base::EventFoo(/* ... */) that calls inside object->on_event_foo(/* .. */). This is because I cannot give a member function as a callback to a C library.
But creating too much callbacks make my wrapper slower. So, I want to connect only the callback that the user wants, ie knowing the functions there are overriden by him.
Disclaimer: I've been notified that this behavior is unspecified since it relies on comparing virtual member function pointers:
[expr.eq] ... if either is a pointer to a virtual member function, the result is unspecified.
Wording is present in all C++ standards (that I could check). Your results may vary.
If you are willing to change a few things, you can use the curiously recurring template pattern to determine if the function is overridden
#include <iostream>
template <class Derived>
struct Base
{
virtual void on_event() {}
void raise_event()
{
if (&Derived::on_event == &Base::on_event)
std::cout << "not overridden" << std::endl;
else
std::cout << "overridden" << std::endl;
}
};
struct Concrete1 : Base<Concrete1>
{
virtual void on_event() override {}
};
struct Concrete2 : Base<Concrete2>
{
// no override
};
int main()
{
Concrete1 c1;
Concrete2 c2;
c1.raise_event(); // prints overridden
c2.raise_event(); // prints not overridden
return 0;
}
The statement &Derived::on_event == &Base::on_event should be resolved at compile-time (if that's what you're worried about) and the if can be optimized away.
Though I agree with others' opinions that this seems like a poor pattern. It would be much simpler to have the base class have empty event handlers like you already have.
Don't use virtual methods at all. If all you want is given some concrete type, Concrete, to hook it up to a bunch of callbacks based on the presence of member functions then we can use templates.
For a given type and function name, we can determine if &T::func exists at compile time. If it does, we add that callback. So we end up with a whole bunch of things like:
template <class T>
void setup_cbs(T& object) {
T* ptr_to_object = ...; // store somewhere
static_if<has_on_event_foo<T>>(
[](auto ptr){
add_event_foo_callback(ptr, [](void* p, int i) {
using U = decltype(ptr);
static_cast<U>(p)->on_event_foo(i);
})
}),
[](auto ){}
)(ptr_to_object);
I'm assuming the callback adder takes a pointer and a callback. You will separately have to figure out how to store the pointers, but that seems easier.
With modern c++ you can do this:
if constexpr (!std::is_same_v<decltype(&Derived::foo), decltype(&Base::foo)>) {
std::cout << "overrided" << std::endl;
}
You may want to define a macro like this:
#define OVERRIDED(B, D, name) !std::is_same_v<decltype(&B::name), decltype(&D::name)>