Code:
typedef void(*callbackType) (int);
callbackType globalCallback;
void setit(callbackType callback) {
globalCallback = callback;
}
int main() {
int localVar = 5;
setit([](int num) {
std::cout << localVar; // there is an error here
});
}
I need to use localVar in lambda function that i send to setit
I guess i have to use [&]{ }
But how can i do it? How should i declare setit and globalCallback?
There are some problems with the code above.
If you didn't need to capture anything, you could use + with lambda to convert it to a function pointer:
typedef void(*callbackType)(int);
callbackType globalCallback;
void setit(callbackType callback) {
globalCallback = callback;
}
int main() {
setit(+[](int){});
}
But this trick works with capturless lambdas only.
One possible solution is to change callbackType and use std::function instead:
using callbackType = std::function<void(int)>;
callbackType globalCallback;
void setit(callbackType callback) {
globalCallback = callback;
}
int main() {
int localVar = 5;
setit([localVar](int num) {
std::cout << localVar; // there is an error here
});
}
which works well.
Related
I need to use a member function as a callback function.
In python, it can be done like this:
CALLBACK = ctypes.CFUNCTYPE(None, ctypes.c_int)
cb = CALLBACK(self.func)
But cb=(callback_t)this->func; doesn't compile in c++.
I wrap it with a lambda function, but it still doesn't compile.
typedef void (*callback_t)(int);
callback_t cb;
class A {
public:
int i = 0;
A() {
cb = reinterpret_cast<callback_t>([this](int i2) mutable { func(i2); });
}
void func(int i1) {
i = i1;
}
};
int main() {
A aa;
cb(3);
return 0;
}
I have a question on callbacks. Previously, I am associating my callbacks to a class Q
class Q{
using Callback = std::function<void(char*, int)>;
Q:Q();
Q:~Q();
void Q::RegisterCB(Callback callbackfunc)
{
callback_func = callbackfunc;
}
void Q:someEvent()
{
callback_func();
}
};
void handleCallback( char*, int)
{
// perform some routine
}
// from my main file
int main()
{
Q q;
q.RegisterCB(&handleCallback);
}
It works well for me. However, when I need to transfer the handleCallback function to another class for cleaner code. I have problem with using same code
class R{
void R::handleCallback( char*, int)
{
// perform some routine
}
void R::someOp()
{
// q is some member variables of R
q.RegisterCB(&R::handleCallback, this);
}
};
However, i run into some problems of saying there is a "no matching function for call to .....". I thought it was just simply assigning from function name to class function name
May I have a hint to where I might go wrong?
Regards
&R::handleCallback has the type void (R::*)(char*, int), which is not convertible to std::function<void(char*, int)>.
Also, RegisterCB takes one argument, not two.
The most straightforward fix is to wrap the call in a lambda function,
q.RegisterCB([this](char* p, int x) { handleCallback(p, x); });
Example on how to use a lambda function to register a member function of an instance of R as event handler. (I replaced char* with string_view out of habit, it's not essential for this example). The use of "const" wherever you can is a recommendation.
#include <functional>
#include <string_view>
#include <iostream>
class Q
{
public:
// use const arguments, the callback is not supposed to change them
// just passing information on to callback
using callback_t = std::function<void(const std::string_view&, const int)>;
// initialize callback with a (lambda) function that does nothing
// this prevents the need for a check if callback has been set or not
// (Pattern : Null Strategy)
Q() :
m_callback_func( [](const std::string_view&,const int) {} )
{
}
~Q() = default;
void RegisterCallback(callback_t fn)
{
m_callback_func = fn;
}
void Event(const std::string_view& string, const int value)
{
m_callback_func(string,value);
}
private:
callback_t m_callback_func;
};
void handleCallback(const std::string_view& string, const int value)
{
std::cout << string << ", " << value << "\n";
}
class R
{
public:
void handleCallback(const std::string_view& string, const int value)
{
std::cout << string << ", " << value << "\n";
}
};
// from my main file
int main()
{
Q q1;
q1.RegisterCallback(handleCallback);
q1.Event("Hello", 42);
// to pass a callback to an instance of a class
// you can use a lambda function https://en.cppreference.com/w/cpp/language/lambda
R r;
Q q2;
q2.RegisterCallback([&r](const std::string_view& string, const int value)
{
r.handleCallback(string,value);
});
q2.Event("World",21);
return 0;
}
This is my attempt:
#include <iostream>
#include <functional>
class Voice;
class EnvelopeMultiPoints
{
public:
std::function<double(Voice &, double)> mCallback;
void SetupModulation(std::function<double(Voice &, double)> callback, int paramID) {
mCallback = callback;
}
};
class Voice
{
public:
EnvelopeMultiPoints mEnvelopeMultiPoints;
};
class VoiceManager
{
public:
Voice mVoices[16];
inline void UpdateVoices(std::function<void(Voice &)> callback) {
for (int i = 0; i < 16; i++) {
callback(mVoices[i]);
}
}
static void SetupEnvelopeMultiPointsModulation(Voice &voice, std::function<double(Voice &, double)> callback, int paramID) {
voice.mEnvelopeMultiPoints.SetupModulation(callback, paramID);
}
};
class Oscillator
{
public:
double ModulatePitch(Voice &voice, double currentValue) {
// somethings with voice
return currentValue * 10.0;
}
};
int main()
{
VoiceManager voiceManager;
Oscillator *pOscillator = new Oscillator();
int param = 100;
auto callback = std::bind(&Oscillator::ModulatePitch, pOscillator, std::placeholders::_1, std::placeholders::_2);
voiceManager.UpdateVoices(std::bind(&VoiceManager::SetupEnvelopeMultiPointsModulation, std::placeholders::_1, callback, param));
Voice voice = voiceManager.mVoices[0];
std::cout << voice.mEnvelopeMultiPoints.mCallback(voice, 1.0) << std::endl;
delete pOscillator;
}
I create a sort of Voice Updater "basic" iterator, which I can pass any kind of functions later. It iterates all voices and pass the function I need for that iteration.
But it seems I'm wrong on bind the Oscillator::ModulatePitch function to pass to the Updater?
Where am I wrong here?
As pergy wrote in its comment, if you use std::function<double(Voice &, double)> callback = ... instead of auto, it works. The reason is that it forces a conversion from an bind object to a std::function.
If you do
auto callback1 = std::bind(&Oscillator::ModulatePitch, pOscillator, std::placeholders::_1, std::placeholders::_2);
std::function<double(Voice &, double)>callback2 = std::bind(&Oscillator::ModulatePitch, pOscillator, std::placeholders::_1, std::placeholders::_2);
std::cout << typeid(callback1).name();
std::cout << typeid(callback2).name();
you will see that the returning types are differents. And in this case, the second bind tries to build its object using the second type (which does not work). I think there is an issue with the conversion operator (from bind to std::function) not being called by the external bind.
I am trying to wrap a C++ layer over libuv, and using lambda for callback functions. However gcc is erroring out.
Here is the minified version:
#include <uv.h>
class Test {
public:
void on_conn(uv_stream_t *server, int status) { }
void test() {
uv_tcp_t server;
auto err = uv_listen((uv_stream_t*)&server,
100,
[this] (uv_stream_s *server, int status) -> void {
this->on_conn(server,status);
});
}
};
Test t;
The relevant declarations in libuv are:
# define UV_EXTERN /* nothing */
struct uv_stream_s { ... };
typedef struct uv_stream_s uv_stream_t;
typedef void (*uv_connection_cb)(uv_stream_t* server, int status);
UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
The error g++ is giving:
$ g++ --version
g++ (GCC) 6.1.1 20160501
<<--ERROR--{reformatted}-->>
t.cpp:15:7: error: cannot convert
‘Test::test()::<lambda(uv_stream_s*, int)>’ to
‘uv_connection_cb {aka void (*)(uv_stream_s*, int)}’
for argument ‘3’ to ‘int uv_listen(uv_stream_t*, int, uv_connection_cb)’
}));
What exactly is broken here ? Any way to make this work ?
UPDATE:
More fun .. this in body of lambda does something ; first call works, second doesn't.
int cfunc( void cb() );
class Test {
public:
void d(){}
void test() {
cfunc( [=] () {});
cfunc( [=] () { this->d(); });
//cfunc( [this] () { });
//cfunc( [&this] () { });
}
};
t.cpp:10:34: error: cannot convert ‘Test::test()::<lambda()>’ to ‘void (*)()’ for argument ‘1’ to ‘int cfunc(void (*)())’
cfunc( [=] () { this->d(); });
A capturing lambda cannot be converted to a function pointer, only a non-capturing can:
//Lambda captures 'this', and so cannot be converted to function pointer
[this](uv_stream_s *server, int status) -> void {
this->on_conn(server,status);
}
Maybe you can use a trick like the following one:
class Test;
struct my_uv_tcp_t: uv_tcp_t {
Test *test;
};
class Test {
public:
Test(): server{} { server.test = this; }
void on_conn(uv_stream_t *server, int status) { }
static void cb(uv_stream_t *server, int status) {
auto srv = static_cast<my_uv_tcp_t*>(server);
srv->test->on_conn(server, status);
}
void test() {
auto err = uv_listen((uv_stream_t*)&server, 100, Test::cb);
}
private:
my_uv_tcp_t server;
};
The stream is given back once something happens on it and the handle of it is nothing more than a naked pointer.
You can use that same stream to store the information of the controller (the instance of the Test class in your case) and cast the stream to its original form when you receive it.
Otherwise, use the data field that is part of the handle if it's still unused.
It should be work. I had same problem, so I sent current object to lambda over handle object property.
#include <uv.h>
class Test {
public:
void on_conn(uv_stream_t *server, int status) { }
void test() {
uv_tcp_t server;
server.data = this;
auto err = uv_listen((uv_stream_t*)&server,
100,
[] (uv_stream_s *server, int status) -> void {
auto self = (Test*)server->data;
self->on_conn(server,status);
});
}
};
Test t;
I did quite a bit of searching, but the combination of * () and class scope has greatly hindered me in understanding of the syntax, with each edit throwing a new error, any help guys?
What I'm trying to do:
Declare a std::vector of pointers to member functions found in MyClass.h
Assign the actual member functions to the std::vector in MyClass.cpp's constructor
The member functions are not static
Thanks!
I'm curious where you're going to use them from. You see in order to call a C++ class member function you need to have an instance pointer with which to call it (each member function needs a this in order to access the class state). So normally you'd wrap the member function pointer together with the instance pointer with std::bind and then maybe store the result in std::function. To put them in vector they're all going to need the same signature.
Is this the kind of thing you were looking for:
class P
{
typedef std::function<void (void)> func_t;
std::vector<func_t> functions;
public:
P()
{
functions.push_back(std::bind(&P::foo1, this));
functions.push_back(std::bind(&P::foo2, this));
functions.push_back(std::bind(&P::foo3, this));
}
void foo1(void)
{
std::cout << "foo1\n";
}
void foo2(void)
{
std::cout << "foo2\n";
}
void foo3(void)
{
std::cout << "foo3\n";
}
void call()
{
for(auto it = functions.begin(); it != functions.end(); ++it)
{
(*it)();
}
}
};
int main()
{
P p;
p.call();
}
After further clarification from the OP I'll propose this:
class P
{
typedef std::function<void (void)> func_t;
std::map<const char*, func_t> functions;
public:
P()
{
functions["foo1"] = std::bind(&P::foo1, this);
functions["foo2"] = std::bind(&P::foo2, this);
functions["foo3"] = std::bind(&P::foo3, this);
}
void foo1(void)
{
std::cout << "foo1\n";
}
void foo2(void)
{
std::cout << "foo2\n";
}
void foo3(void)
{
std::cout << "foo3\n";
}
void call_by_name(const char* func_name)
{
functions[func_name]();
}
};
int main()
{
P p;
p.call_by_name("foo1");
p.call_by_name("foo2");
p.call_by_name("foo3");
}
You can use member function pointers like this (the C++11 is unrelated to that part):
struct S {
int foo(){std::cout<<"foo"; return 0;}
int bar(){std::cout<<"bar"; return 0;}
};
int main() {
std::vector<int(S::*)()> funcs{&S::foo, &S::bar};
S s;
for (auto func : funcs) {
(s.*func)();
}
}
However, if you use C++11, std::function can make it a bit cleaner:
std::vector<std::function<int(S &)>> funcs{&S::foo, &S::bar};
S s;
for (auto func : funcs) {
func(s);
}
If you use C++03, Boost has boost::function, which is similar.