First off, forgive me on the title. Not really sure how to ask this question:
I have an application that I need to convert to a console application (note the application runs fine as a VCL style windows app). The app uses a few 3rd party widgets that have callback functions. However, when I attempt to compile it, I get 'cannot convert ...' errors, like this:
Cannot convert 'void(Tobject *, TErrorEventParams *)' to 'TErrorEvent'
TErrorEvent is defined as:
typedef void __fastcall (__closure* TErrorEvent)(System::TObject* Sender, TErrorEventParams *e);
The line causing the error is:
handler->OnError = errorHandler;
The code for errorHandler is:
void __fastcall errorHandler(System::TObject* Sender, TErrorEventParams *e)
{
memoLine = e->Description;
updateLog();
}
A __closure type is a pointer to a non-static class method. The compiler does not allow you to assign a standalone non-class function where a __closure is expected. It requires a pointer to a method of a class object. Karem's answer shows you one way to accomplish that.
However, there IS a way to use a non-class function, using the helper TMethod struct (which is how a __closure is implemented behind the scenes).
First, add an explicit 'this' parameter to your event handler:
void __fastcall errorHandler(void *This, TObject* Sender, TErrorEventParams *e)
{
memoLine = e->Description;
updateLog();
}
And then assign the event handler like this:
TMethod m;
m.Code = &errorHandler
m.Data = NULL; // any value you want to pass to the 'This' parameter...
handler->OnError = reinterpret_cast<TErrorEvent&>(m);
Have a look at this documentation:
http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Closure
In short:
TErrorEvent is defined as a pointer to a class member function. So errorHandler has to be declared as a class member function.
The implementation could look somewhat like this:
class TMyClass
{
private:
TMyHandler* handler;
void __fastcall errorHandler(System::TObject* Sender, TErrorEventParams *e);
public:
__fastcall TMyClass();
} my_dummy_class;
__fastcall TMyClass::MyClass()
{
//handler has to be created
handler->OnError = errorHandler;
}
void __fastcall TMyClass::errorHandler(System::TObject* Sender, TErrorEventParams *e)
{
memoLine = e->Description;
updateLog();
}
Related
I'm using C++Builder 10.4.2 and having a problem with qsort. I rarely use qsort so I might be making a clumsy mistake. Array 'buffer' is a 2D 'char' array with more than 26,000 rows of single words.
This is the call:
qsort((void *)buffer,wordcount,sizeof(buffer[1]),sort_function);
This is the compare function:
int TForm::sort_function(const void *a, const void *b)
{
return( strcmp((char *)a,(char *)b) );
}
This is the error message. Notice that it's complaining about sort_function for 4th argument:
search.h(46): candidate function not viable: no known conversion from 'int (__closure *)(const void *, const void *)' to 'int (*)(const void *, const void *) __attribute__((cdecl))'
What is 'int (__closure *)'? Is there a way to fix my compare function?
__closure is a Borland compiler extension for obtaining a pointer to a non-static class method, without regard to the type of class being used. This is most commonly used in VCL/FMX components, which allow you to assign event handlers from any class you want, which is not something that standard C++ typically allows you to do.
qsort() expects a C-style function pointer in the 4th parameter. You can't get such a pointer to a non-static class method.
To solve this, you need to use either:
a standalone function
a static class method
a non-capturing C++ lambda (C++11 or higher only)
Since your sort_function() does not need access to your TForm object, declaring sort_function() as static would be the simplest fix:
// .h
class TForm
{
...
private:
static int sort_function(const void *a, const void *b);
void doSomething();
...
};
// .cpp
int TForm::sort_function(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
void TForm::doSomething()
{
...
qsort(buffer, wordcount, sizeof(buffer[1]), sort_function);
...
}
However, it really should be a standalone function instead since it really has no relation to your TForm class at all:
// .cpp
static int sort_function(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
void TForm::doSomething()
{
...
qsort(buffer, wordcount, sizeof(buffer[1]), sort_function);
...
}
Using C++ 17, I'm looking for a way to store a lambda that captures the this pointer, without using std::function<>. The reason to not using std::function<> is that I need the guaranty that no dynamic memory allocations are used. The purpose of this, is to be able to define some asynchronous program flow. Example:
class foo {
public:
void start() {
timer(1ms, [this](){
set_pin(1,2);
timer(1ms, [this](){
set_pin(2,1);
}
}
}
private:
template < class Timeout, class Callback >
void timer( Timeout to, Callback&& cb ) {
cb_ = cb;
// setup timer and call cb_ one timeout reached
...
}
??? cb_;
};
Edit: Maybe it's not really clear: std::function<void()> would do the job, but I need / like to have the guaranty, that no dynamic allocations happens as the project is in the embedded field. In practice std::function<void()> seems to not require dynamic memory allocation, if the lambda just captures this. I guess this is due to some small object optimizations, but I would like to not rely on that.
You can write your own function_lite to store the lambda, then you can use static_assert to check the size and alignment requirements are satisfied:
#include <cstddef>
#include <new>
#include <type_traits>
class function_lite {
static constexpr unsigned buffer_size = 16;
using trampoline_type = void (function_lite::*)() const;
trampoline_type trampoline;
trampoline_type cleanup;
alignas(std::max_align_t) char buffer[buffer_size];
template <typename T>
void trampoline_func() const {
auto const obj =
std::launder(static_cast<const T*>(static_cast<const void*>(buffer)));
(*obj)();
}
template <typename T>
void cleanup_func() const {
auto const obj =
std::launder(static_cast<const T*>(static_cast<const void*>(buffer)));
obj->~T();
}
public:
template <typename T>
function_lite(T t)
: trampoline(&function_lite::trampoline_func<T>),
cleanup(&function_lite::cleanup_func<T>) {
static_assert(sizeof(T) <= buffer_size);
static_assert(alignof(T) <= alignof(std::max_align_t));
new (static_cast<void*>(buffer)) T(t);
}
~function_lite() { (this->*cleanup)(); }
function_lite(function_lite const&) = delete;
function_lite& operator=(function_lite const&) = delete;
void operator()() const { (this->*trampoline)(); }
};
int main() {
int x = 0;
function_lite f([x] {});
}
Note: this is not copyable; to add copy or move semantics you will need to add new members like trampoline and cleanup which can properly copy the stored object.
There is no drop in replacement in the language or the standard library.
Every lambda is a unique type in the typesystem. Technically you may have a lambda as a member, but then its type is fixed. You may not assign other lambdas to it.
If you really want to have an owning function wrapper like std::function, you need to write your own. Actually you want a std::function with a big enough small-buffer-optimization buffer.
Another approach would be to omit the this capture and pass it to the function when doing the call. So you have a captureless lambda, which is convertible to a function pointer which you can easily store. I would take this route and adapter complexer ways if really nessessary.
it would look like this (i trimmed down the code a bit):
class foo
{
public:
void start()
{
timer(1, [](foo* instance)
{
instance->set_pin(1,2);
});
}
private:
template < class Timeout, class Callback >
void timer( Timeout to, Callback&& cb )
{
cb_ = cb;
cb_(this); // call the callback like this
}
void set_pin(int, int)
{
std::cout << "pin set\n";
}
void(*cb_)(foo*);
};
I am using SNMP++ library in my project and everything works fine. However, there is a method where I need to get callback in my .mm file. Now when I am creating a block and passing it to that function as parameter, it throws an error "No matching member function for call to 'get_bulk'". Here is the piece of code:
void(^callbackFunc)(int,Snmp*,Pdu&,SnmpTarget&,void*);
callbackFunc = ^(int i,Snmp* s,Pdu& p,SnmpTarget& t,void* v) {
};
snmp.get_bulk(pdu, *target, l_repeaters, l_repetitions,callbackFunc);
Also, here is the function signature for "get_bulk" function:
int Snmp::get_bulk(Pdu &pdu, // pdu to use
const SnmpTarget &target, // destination target
const int non_repeaters, // number of non repeaters
const int max_reps, // maximum number of repetitions
const snmp_callback callback,// callback to use
const void * callback_data) // callback data
{
pdu.set_type( sNMP_PDU_GETBULK_ASYNC);
return snmp_engine( pdu, non_repeaters, max_reps, target,
callback, callback_data);
}
What should I pass in 'callback' type?This is the typedef for SNMP_callback:
typedef void (*snmp_callback)(int reason, Snmp *session,
Pdu &pdu, SnmpTarget &target, void *data);
I am stuck on this for the past 4-5 hours now and I can't figure out how to resolve this.
Apple's blocks are not convertible to function pointers, as they also contain data (captured variables, etc.) and a reference counting mechanism. You will need to pass a free function, static C++ class member function, or a C++ non-capturing lambda as the callback.
The lambda is the closest syntactically to a block; only non-capturing lambdas are convertible to a function pointer, however, so you will need to do the capturing "by hand" by passing a pointer to a context struct or similar through the void* callback_data argument which presumably is passed through to the callback as void* data.
The lambda will look something like this:
snmp_callback callback =
[](int reason, Snmp *session, Pdu &pdu, SnmpTarget &target, void *data)
{
// context_struct_type* context = static_cast<context_struct_type*>(data);
};
I have a question about syntax of function parameter in Swift.
I want to get message through C based callback function from library, so I make a function with Objective-C as below:
void foo(char *arg) {
NSLog(#"%s", log);
}
Then, I register foo to MainController interface with Objective-C like this.
typedef void (*CB)(char *);
void addFoo(CB func);
...
addFoo(&foo);
The above code is a simplified representation, but it print log for library well.
Now, I have to change the language from Objective-C to Swift. Most of the source code has changed, but for the above function, the log is not output normally.
How can I change?
Please help.
I tried to convert directly. This is code.
typealias CB = (String) -> Void
func addCB(cd: CB) {
// ...
}
func foo(pa: String) {
// ...
}
var fooFuc: CB = foo(pa: )
addCB(cd: fooFuc)
The error while creating a button in opencv
argument of type 'void (Window::)(int, void*)' does not match 'cv::ButtonCallback {aka void ()(int, void)}'
class Window{
void ChecKBox(int state, void* val){
// do nothing for now
return;
}
public:
void createCheckbox(){
cv::createButton(checkboxname, CheckBox, NULL, CV_CHECKBOX, 0);
}
};
int main(){
Window w;
w.createCheckBox();
}
I can't seem to find the fix to this problem.
oh, you can't pass in a member function of a class here. think of it, where would the 'this' pointer come from ? (like you call class members like w.CheckBox(1,NULL); there is no 'w' here. )
the highgui interface is a bit limited. it can only call free functions or static members.
so, if your callback function does not need anything from Window, make it static:
class Window {
static void CheckBox(int state, void* val) { /*you can't use 'this' here!*/ return; }
public:
void createCheckBox() { cv::createButton(checkboxname, CheckBox, NULL, CV_CHECKBOX, 0); }
};
int main() {
Window w;
w.createCheckBox();
}