Reputation: 47995
This is my code:
#include <iostream>
#include <stdio.h>
using namespace std;
typedef void (*CallbackType)(double);
class LFO
{
private:
public:
CallbackType target;
inline void Process() {
double value = 1.3;
target(value);
}
};
class ExternalObject
{
private:
public:
double mTest = 1.0;
ExternalObject() {
}
~ExternalObject() {
}
inline void PrintValue(double value) {
cout << "passed: " << value << endl;
}
};
int main ()
{
ExternalObject eo;
LFO lfo;
lfo.target = eo.PrintValue;
lfo.Process();
}
I want to execute within LFO's Process the callback PrintValue of ExternalObject. But it seems I cannot pass lfo.target
in this way? Where am I wrong? (sorry, I'm new to C++; in JavaScript this is the way I'll do it).
Upvotes: 1
Views: 200
Reputation: 42994
The CallbackType
is defined like this:
typedef void (*CallbackType)(double);
This basically is a function taking a double
and returning nothing (void
).
When you assign eo.PrintValue
like this:
lfo.target = eo.PrintValue;
you have a type mismatch: That's because PrintValue
is a non-static member function of the ExternalObject
class. Non-static member functions have a "hidden" additional parameter, which is the this
pointer to the class instance.
It's kind of like the actual declaration of PrintValue
would be:
void ExternalObject::PrintValue(ExternalOject* this, double value)
You can fix that making PrintValue
a static
method of ExternalObject
, as static
methods don't have the additional this
pointer parameter. E.g.:
class ExternalObject {
public:
// Note: you don't need "inline" here
static void PrintValue(double value) {
...
}
P.S. Usually when you have callbacks, a common pattern in C++ is to provide an additional void*
parameter in the callback. This can be used to give some context to the callback function, including passing the aforementioned this
pointer (so a static member-function callback can use the this
pointer to call a non-static method).
P.P.S. That callback style is usually found in C-interface APIs. In C++ you may want to consider std::function
(e.g. std::function<void(double)>
) instead.
You may also consider a design with a class with overloaded operator()
as callback (so called "functor", or "function object"), e.g.:
#include <functional> // for std::function
#include <iostream>
class LFO {
public:
std::function<void(double)> Target;
void Process() {
double value = 1.3;
Target(value);
}
};
class ValuePrinter {
public:
void operator()(double value) const {
std::cout << "passed: " << value << '\n';
}
};
int main() {
LFO lfo;
lfo.Target = ValuePrinter();
lfo.Process();
}
As a different alternative, you can use std::bind
and a placeholder for the double
parameter, e.g. inside main
:
ExternalObject eo;
LFO lfo;
using namespace std::placeholders;
lfo.Target = std::bind(&ExternalObject::PrintValue, &eo, _1);
lfo.Process();
Compilable code:
#include <functional>
#include <iostream>
class LFO {
public:
std::function<void(double)> Target;
void Process() {
double value = 1.3;
Target(value);
}
};
class ExternalObject {
public:
double mTest = 1.0;
ExternalObject() = default;
void PrintValue(double value) {
std::cout << "passed: " << value << '\n';
}
};
int main() {
ExternalObject eo;
LFO lfo;
using namespace std::placeholders;
lfo.Target = std::bind(&ExternalObject::PrintValue, &eo, _1);
lfo.Process();
}
Upvotes: 1