I wrote an Event class as a wrapper around callback functions, implemented as std::functions. This is what it looks like:
class Event
{
public:
Event() : default_handler([]() {});
Event(const std::function<void()> handler) : default_handler(handler);
void SetHandler(std::function<void()> handler)
{
custom_handler = handler;
}
void operator()(void)
{
default_handler();
custom_handler();
}
private:
const std::function<void()> default_handler;
std::function<void()> custom_handler;
};
Then, inside another class, I have an instance of an Event:
class Control
{
public:
Control();
//Should call constructor Event()
Event myEvent1;
//Should call constructor Event(std::function<void()>)
Event myEvent2([]() {/*do stuff... */})
};
This, however, won't compile on VC++, generating error C3646 (unknown override specifier) and error C4430 (missing type specifier - int assumed) for both handlers, with more syntax errors for myEvent2. Where did I go wrong?
When you write
Event myEvent2([]() {/*do stuff... */});
compiler treats myEvent2 as the member function, not constructor call.
You should use {} syntax:
Event myEvent2{[]() {/*do stuff... */}};
Demo
As syntax for default member initializer is
member = value;
or
member{value};
but NOT
member(value); // Invalid syntax
Related
I'm writing a C++ code with the Arduino framework. It uses the avr-gcc compiler. I cannot use std::function.
I set up a class with a callback and a simple example how I use it:
class GPI
{
public:
typedef void(*GpiCallback)(bool value);
GPI();
void Begin(byte pin, GpiCallback callback);
void Loop();
private:
GpiCallback _callback;
};
GPI::GPI() { }
void GPI::Begin(byte pin, GpiCallback callback)
{
// do something
_callback = callback;
}
void GPI::Loop()
{
// do something
_callback(value);
}
in another class:
class Engine
{
public:
Engine();
void Init();
// other members
private:
GPI _gpi;
bool _foo;
// other members
};
void Engine::Init()
{
_gpi.Begin(PIN_BUTTON, [](bool value)
{
Serial.print(F("[GPI] Button pressed"));
});
}
All this stuff works.
Now I want to access, inside the lambda function, to the other members of my Engine class.
Reading the documentations about lambdas I thought it should be enough to capture the this variable, i.e.:
_gpi.Begin(PIN_BUTTON, [this](bool value)
{
Serial.print(F("[GPI] Button pressed"));
_foo = true;
});
but I get a compiler error:
no conversion function exists from "lambda [](bool value)->void" to "GPI::GpiCallback"
I don't fully understand this message, actually. It reports the correct signature of the callback (even without the captured variable).
Why does capturing a variable lead to a wrong lambda signature?
I have a Callback which looks like this:
typedef void(*Callback)(EventInfo event_info);
This can be used with free functions, but when I try to use class methods it fails with the error :
Error C2276 '&': illegal operation on bound member function expression
How should I go about this and make it so that it also accepts a class method just like a free function. That is I could simply do :
struct MyClass
{
void some_methods(EventInfo info)
{
sth;
}
}
void some_functions(EventInfo info)
{
sth;
}
int main()
{
MyClass obj;
myobj.AddOnSthChanged(obj.somemethods);
myobj.AddOnSthChanged(some_functions);
...
Pointers on function are limited to .. pointers on function.
To allow any callable, you have to use template or type erasure as std::function:
using Callback = std::function<void(EventInfo)>;
struct MyClass
{
Callback callback;
};
struct A
{
void foo(EventInfo) {}
};
void bar(EventInfo) {}
int main()
{
EventInfo event;
MyClass c1{bar};
c1.callback(event); // bar(event);
A a;
MyClass c2{ [&a](EventInfo event){ a.foo(event); }};
c1.callback(event); // a.foo(event);
}
I want to pass my class Worker a pointer to a funtion, but something is wrong when im calling the constructor...
Worker.h
class Worker : public QObject
{
Q_OBJECT
public:
Worker(void (*process)());
public slots:
void work();
signals:
void error(QString error);
void paused();
private:
void (*_task)();
};
Worker.cpp:
Worker::Worker(void (*task)())
{
_task = task;
}
void Worker::work()
{
_task();
paused();
}
This is what i want to do...
Worker should perform a function call of any function.
(Update is a void without attributes, not static or const etc.)
Main.cpp:
_worker = new Worker(someClass->Update());
First, when a function is a non static member function of a class, its first argument is the object from which its called.
In your example, the real code for your function Update() from the object someClass is "void Update(&someClass)"
Secondly, when you do Update(), you call the function and so, takes its return in your Worker constructor.
To use member function pointers, the syntax is : &ClassType::FunctionName
To use 'normal' function pointers, the syntax is : &FunctionName
In your exemple, you can for exemple turn Update function to static and change your constructor like this :
_worker = new Worker(&someClassType::Update);
Like someone said in the comments, if you want to improve your code, learn about std::function from C++11
Just a variant of FĂ©licie's answer.
If you want to be able to pass methods operating on arbitrary objects, the C++11 way will be to use std::function and std::bind.
If for any reason you must use a pre C++11 system, you will have to revert to the C-ish style of passing arbitrary arguments, the good old void * type:
void someClassUpdateWrapper(void *obj) {
SomeClassType someClass = static_cast<SomeClassType *>(obj);
someClass->Update();
}
You will have to slightly change your declarations:
class Worker : public QObject
{
Q_OBJECT
public:
Worker(void (*process)(), void *obj);
...
private:
void (*_task)();
void *_obj;
};
then:
Worker::Worker(void (*task)(), void *obj;)
{
_task = task;
_obj = obj;
}
void Worker::work()
{
_task(_obj);
paused();
}
and finaly:
_worker = new Worker(someClassUpdateWrapper, static_cast<void *>(someClass));
But this looses all the possible type controls allowed by the C++11 way - the reason why std::function and std::bind were invented...
I have a two-layer object structure where the contained object has a deadline_timer and the outer object has the handler function, as:
class Internal
{
asio::deadline_timer t;
public:
void QueueTick(void (*handler)(boost::system::error_code const&))
{
t.expires_from_now(posix_time::millisec(250));
t.async_wait(handler);
}
};
class ForClients
{
Internal I;
void OnTick(boost::system::error_code const&) { /*...*/ }
void Init()
{
I.QueueTick(boost::bind(&cdevXcite::OnTick, this, _1));
}
};
The QueueTick() call is failing to compile in MSVS 2008 with "cannot convert parameter 1 from 'boost::_bi::bind_t' to 'void (__cdecl *)(const boost::system::error_code &)'".
If I make the timer member public and make a direct call to I.t.async_wait() with the same argument, it succeeds. Clearly, the handler's signature is more special than what I've used in the QueueTick declaration; however, I can't find a symbol that defines it and I don't know how to interpret the metaprogramming going on inside the basic_deadline_timer<> template.
An asio timer's async_wait can be called with any callable type that can be called with a boost::system::error_code const& argument. There isn't a single type anywhere that defines it, it just has to be callable with the documented argument type.
The type of your QueueTick parameter is one such callable type, a pointer to a plain ol' non-member function with the right signature:
void QueueTick(void (*handler)(boost::system::error_code const&))
But the result of boost::bind is a class type with an overloaded operator() which is not convertible to that function pointer type.
There are a few ways to solve this, but the simplest is probably to follow async_wait itself and write QueueTick as a function template, accepting any type:
class Internal
{
asio::deadline_timer t;
public:
template<WaitHandle>
void QueueTick(WaitHandle handler)
{
t.expires_from_now(posix_time::millisec(250));
t.async_wait(handler);
}
};
The rest of the code would be unchanged.
If that's not an option (e.g. because QueueTick needs to be virtual) then you could use boost::function with can hold any callable object of the right signature:
class Internal
{
asio::deadline_timer t;
public:
typedef boost::function<void(boost::system::error_code const&)> handler_type;
void QueueTick(handler_type handler)
{
t.expires_from_now(posix_time::millisec(250));
t.async_wait(handler);
}
};
This will have a small overhead compared to the template version, due to constructing the boost::function object.
If you can use C++11, you can do something like:
class Internal
{
asio::deadline_timer t;
public:
void QueueTick(const std::function<void(const boost::system::error_code&)>& handler)
{
t.expires_from_now(posix_time::millisec(250));
t.async_wait(handler);
}
};
class ForClients
{
Internal I;
void OnTick(const boost::system::error_code& ec) { /*...*/ }
void Init()
{
I.QueueTick([this](const boost::system::error_code& ec) { OnTick(ec); });
}
};
class Action {
public:
void operator() () const;
}
class Data {
public:
Data();
~Data();
Register(Action action) { _a = action; }
private:
Action _a;
}
class Display {
public:
Display(Data d) { d.Register( bind(Display::SomeTask, this, _1) ); }
~Display();
void SomeTask();
}
I want to bind the private member _a of Data to a member function of Display, but I get compile errors saying my argument types don't match when I call d.Register, what am I doing wrong? Thanks.
What you're trying to do is not completely clear, but I'll assume that "bind" is boost::bind (or tr1::bind).
A couple of problems with bind(Display::SomeTask, this, _1):
It should be &Display::SomeTask
The _1 placeholder makes no sense because that creates an unary function object and:
Display::SomeTask takes no arguments
Action::operator() takes no arguments
Using Boost.Function and Boost.Bind, here's what you could write to acheive what I guess you're trying to do:
typedef boost::function<void(void)> Action;
class Data {
public:
Data();
~Data();
Register(Action action) { _a = action; }
private:
Action _a;
};
class Display {
public:
Display(Data d) { d.Register( bind(&Display::SomeTask, this) ); }
~Display();
void SomeTask();
};
I cannot see what 'bind' returns, but I absolutely sure this is not compatible with Action class. Also you are using 'copy semantic', so if Action has empty implmentation, you will never get desired.
Try change Register(Action* action), and allow 'bind' to return some child of Action class.
Also review possibility to migrate to templates - than you even can exclude Action class at all
template <class A>
class Data { ...
Register(A action)...
A _a;
...
In this case you could be able to use as classes with overridden operator() as functions without argument.
First, you have to use &Display::SomeTask and give Register a return type, and then it depends on your needs
The wrapper should call SomeTask on *this: Omit _1.
The wrapper should call SomeTask on a passed Display object: Shift _1 in place of this.
Then, boost::bind returns some complicated synthesized type that will call the specified function. You need a way to store it, which is where boost::function comes handy. This is how you can do it
class Display; // forward-declaration
class Data {
public:
Data();
~Data();
template<typename Action>
void Register(Action action) { _a = action; }
private:
boost::function<void(Display&)> _a;
// if wrapper should call it on `*this`
// boost::function<void()> _a;
}
class Display {
public:
// this currently makes no sense. You pass a copy. Probably you
// should consider pass-by-reference or processing "d" further.
Display(Data d) { d.Register( bind(&Display::SomeTask, _1) ); }
// wrapper should call it on `*this`:
// Display(Data d) { d.Register( bind(&Display::SomeTask, this) ); }
~Display();
void SomeTask();
}
Then it should work.