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)
Related
I want to be able to pass functions with an object of class I as parameter, where I inherits from D, to FD constructor::
class D {}; class I: public D {};
FD(std::function<void(D*)> f): _f(f) {}
void test(I*) { std::cout << "Success" << std::endl; }
FD fd(test); fd.call();
As I have been researching I should implement a type conversion, but I do not know a clean way and did not find answers addressing type conversions appliable to my case.
Here is the full code:
#include <functional>
#include <iostream>
class D {}; class I: public D {};
class FD {
protected:
std::function<void(D*)> _f;
public:
explicit FD(std::function<void(D*)> f): _f(f) {}
void call() { _f(0); }
};
void test(I*) { std::cout << "Success" << std::endl; }
int main () {
FD fd(test); fd.call();
}
I get:
test.cpp: In function ‘int main()’:
test.cpp:17:13: error: no matching function for call to ‘FD::FD(void (&)(I*))’
FD fd(test); fd.call();
^
test.cpp:10:14: note: candidate: FD::FD(std::function<void(D*)>)
explicit FD(std::function<void(D*)> f): _f(f) {}
^~
test.cpp:10:14: note: no known conversion for argument 1 from ‘void(I*)’ to ‘std::function<void(D*)>’
I have also tried using int and double:
#include <functional>
#include <iostream>
class FD {
protected:
std::function<void(double)> _f;
public:
explicit FD(std::function<void(double)> f): _f(f) {}
void call() { _f(0); }
};
void test(int v) { std::cout << "Success" << std::endl; }
int main () {
FD fd(test); fd.call();
}
With output:
Success
It's possible to explain the reason for the compilation error in excruciating technical detail, and why you cannot do what you want to do, in C++, but perhaps this fundamental reason will be clear to you if you consider a very simple thought experiment:
std::function<void(D*)> f;
You surely understand that this callable object can be called using a pointer to any subclass of D. You might have some other class called J that also inherits from D, and so this is perfectly acceptable:
class J : public D {};
J j;
f(&j);
But you are attempting to do here is construct your std::function using a pointer to a function that takes only I * as a parameter:
void test(I*)
If what you were attempting to do was possible, then this will mean that this test() function can be called, via the std::function<void (D*)> object, using a pointer to J, instead of I. Fail. This is, of course, is not allowed in C++. If the only relationship between two classes is that they all have the same parent class, you simply cannot convert a pointer to one of them to a pointer to the other one. C++ does not work this way.
And the reason why your 2nd example, with ints and doubles work, is because ints and doubles can be converted to each other. The same is not true with pointers to two random classes. A pointer to a class can be converted to a pointer to a different class only in certain, well-defined cases. What you want is not allowed in C++.
The only thing that can happen here is the test() function taking a D * as a parameter, crossing its fingers and attempting to dynamic_cast it to an I * (assuming that D meets the requirements for a dynamic-castable class). And then you will have to decide what happens when this conversion fails.
Of course, you can do the cast like this: FD fd(reinterpret_cast<void(*)(D*)>(test)); but this is UB.
The error is clear - you can't implicitly cast D* to I*. This violates polymorphism.
Are you sure you are not mixing up I and D?
UPD:
I assume downvoting this post means it is not clear. I will try to explain:
Imagine the following:
class D
{
public:
void (*ok)() = +[] { std::cout << "OK"; };
};
class I: public D
{
public:
void (*not_ok)() = ok;
};
ok() can be accesed from D instance while not_ok() cannot. Now you want to call your function taking pointer to I. But that means your function can call not_ok() which is not valid for pointer to D:
void test(I* i)
{
i->ok();
i->not_ok();
}
With raw pointers you can try this:
class FD {
protected:
std::function<void(D*)> _f;
public:
explicit FD(void(*f)(I*)) : _f(reinterpret_cast<void(*)(D*)>(f))
{
}
void call() { _f(new I); }
};
It will print OKOK. But if you replacenew I with new D it will fail on not_ok() call
This is why C++ doesn't allow to implicitly cast pointers (while you still can implicitly cast int to double).
Even if you want to 'hack' your code, C++ has no global type conversion rules. Also, you can't get raw pointer from std::function, therefore, there is no way to do this.
I have a structure, inside it a pointer to function from the same structure. And now I need to call a pointer to function outside the structure. I give an example of the code below:
#include <iostream>
struct test {
void (test::*tp)(); // I need to call this pointer-to-function
void t() {
std::cout << "test\n";
}
void init() {
tp = &test::t;
}
void print() {
(this->*tp)();
}
};
void (test::*tp)();
int main() {
test t;
t.init();
t.print();
(t.*tp)(); // segfault, I need to call it
return 0;
}
(t.*tp)(); is trying to invoke the member function pointer tp which is defined at global namespace as void (test::*tp)();, note that it's initialized as null pointer in fact (via zero initialization1), invoking it leads to UB, anything is possible.
If you want to invoke the data member tp of t (i.e., t.tp) on the object t, you should change it to
(t.*(t.tp))();
^
|
---- object on which the member function pointed by tp is called
If you do want to invoke the global tp, you should initialize it appropriately, such as
void (test::*tp)() = &test::t;
then you can
(t.*tp)(); // invoke global tp on the object t
1 About zero initialization
Zero initialization is performed in the following situations:
1) For every named variable with static or thread-local storage duration that is not subject to constant initialization (since C++14), before any other initialization.
#songyuanyao's answer is valid. However, are you sure you want to use your structure that way? Why not just use inheritance and virtual methods? :
class base_test {
public:
virtual void t() { std::cout << "test\n"; }
void print() { t(); }
};
and then you can subclass it:
class my_test : base_test {
public:
virtual void t() { std::cout << "my test\n"; }
};
In your main() function (or wherever) you could have functions returning pointers or references to the base class, which are actually instances of subclasses. And this way, you don't have to worry about pointers.
The downside is that you have to know about your different tests at compile time (and then not even at the site of use, as I just explained). If you do, I'd go with the common idiom.
I have a pointer to an object 'eventHandler' which has a member function 'HandleButtonEvents':
I call it like this:
eventHandler->HandleButtonEvents();
Now I want to pass a pointer to the member-function 'HandleButtonEvents()' of the class 'EventHandler' as an argument to another the object 'obj' like in this Stackoverflow example:
ClassXY obj = ClassXY(eventHandler->HandleButtonEvents);
The constructor is declared like this:
ClassXY(void(*f)(void));
The compiler tells me:
error : invalid use of non-static member function
What am I doing wrong?
Using std::function and std::bind as suggested in my comment makes it very easy:
#include <iostream>
#include <functional>
class ClassXY
{
std::function<void()> function;
public:
ClassXY(std::function<void()> f)
: function(f)
{}
void call()
{
function(); // Calls the function
}
};
class Handler
{
public:
void HandleButtonEvent()
{
std::cout << "Handler::HandleButtonEvent\n";
}
};
int main()
{
Handler* handler = new Handler;
ClassXY xy(std::bind(&Handler::HandleButtonEvent, handler));
xy.call();
}
See here for a live example.
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?
I'm searching a solution for this for a few days now. Didn't find any question related enough to answer regrettably so here is my question.
Consider the next code:
// dummy class A
class A {
public:
void aFunction() { // <- this is the function I want to point at
cout << "aFunction() is called\n";
}
};
class B {
public:
template <class Class> // get a function pointer
void setFunction( void (Class::*func)() ) {
p_func = func;
}
void (*p_func)(); // the function pointer
}
int main() {
B obj;
objb.setFunction(&A::aFunction);
return 0;
}
I have a compilation error in setFunction() on p_func = func;:
cannot convert from 'void (__thiscall A::* )(void)' to 'void (__cdecl *)(void)'
And I don't seem to be able to get rid of it in any way. I know it has something to do with those invisible this pointers (__thiscall and __cdecl), but I don't know how to handle these. I tried making the member variable p_func a class template too (void (Class::*p_func)()) so it would have the same structure, but it that seems to be illegal to have 2 class templates in one class (why?), thus isn't the correct solution. This time the compiler complains about:
multiple template parameter lists are not allowed
This method (without the template) works perfectly on global functions (which is the workaround I currently use) and I saw the use of it in a library (sfgui), so it should be perfectly possible.
To have some context over why I'd want this: I'm trying to create a button. This button should be able to call whatever function I'd like. For now, I'd like it to call the start() function of an animation class I'm making.
p.s.: I know this example is useless since I can't run p_func: the function isn't static. I still need to add an object pointer (setFunction( void (Class::*func)(), Class* )), but that does not seem to be a problem. And I know about typedef to make a function pointer more readable, but not with a class template.
EDIT
After some more research I think the answer I need not the answer to this question, but rather another one. For once, I noticed that multiple template <class Class> is in fact allowed. However, it is not allowed on member variables since the compiler can't possibly know which class he'll need to use which probably is the reason for the error
multiple template parameter lists are not allowed
which is an odd description. Thanks anyway for the help, you did gave me a better insight.
You cannot convert a pointer-to-member Class::*func to a normal function pointer. They are of different types.
You should turn this:
void (*p_func)(); // the function pointer
into this:
void (class::*p_func)(); // the function pointer
You could also use a std::function<void()> and use boost::bind to bind it.
std::function<void()> fun = boost::bind(class::member_fun, args);
EDIT
What about making your B class a template so you can do this:
#include<iostream>
class A {
public:
void aFunction() { // <- this is the function I want to point at
std::cout << "aFunction() is called\n";
}
};
template<class T>
class B {
public:
void setFunction( void (T::*func)() ) {
p_func = func;
}
void (T::*p_func)(); // the function pointer
void callfunc()
{
(t.*p_func)(); //call pointer to member
}
private:
T t;
};
int main() {
B<A> obj;
obj.setFunction(&A::aFunction);
return 0;
}
Live Example
I found the complete answer myself while searching for a way to save *objects of an unknown type without using templates or void pointers which has been answered here. The solution is a bit dodgy, because you'll have to create a dummy parent which allows for certain conversions.
The idea is that you create a Parent and every object that is allowed to be pointed to must inherit from it. This way you can create a pointer as Parent *obj which can hold multiple types of objects, but of course only classes that inherit from Parent.
The same applies for function pointers. If you define your pointer as void (Parent::*func)() as member variable. You can ask the user a template function pointer template <class Class> setFunction( void (Class::*f)() ), which can hold any pointer to any class. Now you need to cast the function pointer to the desired class, Parent: static_cast<void(Parent::*)()>(f). Mind that this only works when Class inherits from Parent. Otherwise you'll get a compilation error.
Minimal Working Example
#include <iostream>
using namespace std;
// dummy class Parent
class Parent {};
// class A
class A : public Parent { // Mind the inheritance!
public:
A(int n) : num(n) {}
void print() { // <- function we want to point to
cout << "Number: " << num << endl;
}
int num;
}
// class B, will hold the 2 pointers
class B {
public:
B() {}
template <class Class> // will save the function and object pointer
void setFunction( void (Class::*func)(), Class *obj) {
function = static_cast<void(Parent::*)()>(func);
object = obj;
}
void execFunction() { // executes the function on the object
(object->*function)();
}
void (Parent::*function)(); // the function pointer
Parent *object; // the object pointer
}
int main() {
A a(5);
B b;
b.setFunction(&A::print, &a);
b.execFunction();
return 0;
}
I don't really like this solution. A better solution would be that class B could have a function where it returns a bool when the function needs to be executed. This way you could simply place an if statement in the main-function that executes the desired function.
A a(5);
B b;
while (;;) {
if (b.aTest())
a.print();
}
Where B::aTest() is declared as
bool B::aTest();
Hope this helps anyone that comes across the same problem. So it is perfectly possible but pretty dodgy in my opinion, and I don't encourage people using the first method.