There is a callback function type in libevent used by event_new().
typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
I want use lambda with event_callback_fn.
If I use
[](evutil_socket_t fd, short flags, void * _param){}
everything is OK.
But if I use the lambda capture list
[&](evutil_socket_t fd, short flags, void * _param){}
event_new() will not be compiled.
The type alias
void (*event_callback_fn)(evutil_socket_t, short, void *);
is a function pointer. Lambdas can automatically convert to function pointers, when they don't capture anything. As soon as you define a closure (stateful lambda), you can't pass it as an argument of type event_callback_fn.
Related
In boost.asio example of asynchronous UDP server we can find next code:
void start_receive()
{
socket_.async_receive_from(
boost::asio::buffer(recv_buffer_), remote_endpoint_,
boost::bind(&udp_server::handle_receive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
..........
void handle_receive(const boost::system::error_code& error,
std::size_t /*bytes_transferred*/)
According to specification of basic_datagram_socket::async_receive_from function, its prototype is
template<
typename MutableBufferSequence,
typename ReadToken = DEFAULT>
DEDUCED async_receive_from(
const MutableBufferSequence & buffers,
endpoint_type & sender_endpoint,
ReadToken && token = DEFAULT);
when token may be a function with prototype
void handler(
const boost::system::error_code& error, // Result of operation.
std::size_t bytes_transferred // Number of bytes received.
);
I do not understand two things (at least)
How bind work here? It accept handle_receive pointer, udp_server object (what for?) and two placeholders. How does it turn to function that is called at the end of asynchronous call and get context varibles?
How does handle_receive function access a recv_buffer_ which is an argument of async_receive_from function but not of handle_receive?
Bind returns a bound function object. There's extensive documentation about how it works and why you'd use it:
https://www.boost.org/doc/libs/1_77_0/libs/bind/doc/html/bind.html
also see https://en.cppreference.com/w/cpp/utility/functional/bind
udp_server object (what for?)
(Non-static) member functions take an implicit this pointer argument to the class instance (object). So a 2-argument non-static member function void X::foo(int,int) consttakes 3 arguments:X const*, int, int`.
How does handle_receive function access a recv_buffer_ which is an argument of async_receive_from function but not of handle_receive?
recv_buffer_ is a data member of the same class (udp_server), so in handle_receive it is implicitly accessing it as this->recv_buffer_. This is very elementary C++, so I recommend maybe reading a good introduction or book if this is new for you.
When saving the address of a function with a variadic template, the g++ compiler (Version 4.8.2) outputs this error:
address of overloaded function with no contextual type information
The code in question:
template<typename... Args>
void redirect_function(const char *format, Args... args)
{
pLog->Write(format, args...); // or: printf(format, args...);
}
void *fnPtr = (void *)&redirect_function; // The error occurs here.
Here is what I do with this somewhere else:
typedef void (*log_bridge)(const char*, ...);
log_bridge LogWrite;
LogWrite = (log_bridge)fnPtr;
I have no other possibility to this so please don't suggest completely different ways of solving this.
Well. It is simple why it's not possible. You have a clear ambiguousity. redirect_function is not a function; as all template functions it's more like a set of overloads generated from the template for different types of arguments.
The function needs to get instantiated first to be able to get its address, and you provide no necessary information to do this.
In other words the problem is that you cannot possibly know which concrete overload of redirect_function you should use on the problematic line.
The only thing you could do is to provide template arguments explicitly.
C++11 lambdas that does not capture anything can be stored in a function pointer. One just need to ensure that lambda accepts and returns the same parameters as the function pointer.
In GObject library all callbacks has type void(*GCallback) (void). This definition does not anyhow affect signature of the callback though:
The type used for callback functions in structure definitions and
function signatures. This doesn't mean that all callback functions
must take no parameters and return void. The required signature of a
callback function is determined by the context in which is used (e.g.
the signal to which it is connected). Use G_CALLBACK() to cast the
callback function to a GCallback.
In other words, one can pass function like this:
int my_function(int a, char b) {}
by casting its type (that's what G_CALLBACK do):
do_something(G_CALLBACK(my_function));
Unfortunately typecasting does not work with C++11 lambdas:
do_something(G_CALLBACK([](int a, char b) -> int {...});
// Cannot cast from type lambda to pointer type GCallback
Is it possible to use C++ lambdas of arbitrary type in place of GCallback?
UPDATE
Just to clarify, I know that lambda can be casted to a function pointer if their signatures match. My question is in another dimension.
The ISO C standard guarantees that function can be casted forth and back without loosing any precision. In other words one the following expression is valid:
int f(int a){...}
void (*void_f)() = (void (*)())f;
int (*restored_f)(int) = (int (*)(int))void_f;
restored_f(10);
My question is whether the following expression is also valid according to C++11:
int (*f)(int) = [](int a) -> int {};
void (*void_f)() = (void (*)())f;
int (*restored_f)(int) = (int (*)(int))void_f;
restored_f(10);
The following code compiles and works for me (MSVC 2013):
auto lambdaFunc = [](int a, char b) -> int { return 0; };
typedef int (*LambdaType)(int, char);
GCallback fnTest1 = G_CALLBACK((LambdaType)lambdaFunc);
GCallback fnTest2 = G_CALLBACK((LambdaType) [](int a, char b) -> int { return 0; });
do_something(fnTest1);
do_something(fnTest2);
do_something(G_CALLBACK((LambdaType)lambdaFunc));
Lambdas without a capture are implicitly convertible to a pointer to a function by the standard. Though not all compilers support this feature at the moment (https://stackoverflow.com/a/2935230/261217).
Then you can explicitly cast a function pointer to GCallback.
I am using different linker script. In some, a value is defined, in others, it is not defined:
DIRECTORY_ADDRESS = 0x80100000;
DIRECTORY_SIZE = 32M;
At execution, I want a default behavior when this value is not defined, and a special behavior when it is defined.
Classically, I get the values like this:
extern void * DIRECTORY_ADDRESS;
extern void * DIRECTORY_SIZE;
void f() {
void *dir_addr = &DIRECTORY_ADDRESS;
int dir_size = (int)&DIRECTORY_SIZE;
}
My first lead to conditionnaly execute code according to the existence of this value in linker script is the weak atttribute:
extern void * DIRECTORY_ADDRESS __attribute__ ((weak)) = 0x0;
extern void * DIRECTORY_SIZE __attribute__ ((weak)) = 0x0;
void f() {
if ( DIRECTORY_ADDRESS )
// special code
else
// default code
}
But it can't work, as I am initializing the pointer value, and not its address: even an undifined weak symbol has an address. So directory address is always != NULL.
I am pretty sure this problem has already been solved, but I can't find any related problem on the web.
My mistake!
I tried many combination, and this one is actually wrong:
As I am initliazing weak symbols, there are "half weak"
extern void * DIRECTORY_ADDRESS __attribute__ ((weak)) = 0x0;
extern void * DIRECTORY_SIZE __attribute__ ((weak)) = 0x0;
To solve my problem, I just have to let weak symbols uninitialized, then the symbol address will be NULL if they are not defined with a strong symbol:
extern void * DIRECTORY_ADDRESS __attribute__ ((weak));
extern void * DIRECTORY_SIZE __attribute__ ((weak));
Uninitialized globals are weak by default, so you can just use
void * DIRECTORY_ADDRESS;
void * DIRECTORY_SIZE;
If there is no external symbol defined for these names, the value will default to NULL. To force a different default value than NULL, you could use
void * DIRECTORY_ADDRESS __attribute__ ((weak)) = OTHER_VALUE;
void * DIRECTORY_SIZE __attribute__ ((weak)) = OTHER_VALUE;
Note that initializing an extern doesn't really make sense: extern means that the definition is external to the file, but initializing provides a definition. My compiler (gcc 4.4) warns the user of this, and then ignores the extern modifier. This means your example worked as expected for me (even when initializing to 0x0), but maybe your compiler handles this ambiguous situation differently.
I am currently writing a program in C++0x which I am fairly new to.
I am setting up callbacks between objects and using lambda to match the types (like boost::bind() does in ways)
If I call a function in the asio library like:
socket_.async_read_some(buffer(&(pBuf->front()), szBuffer),
[=](const boost::system::error_code &error, size_t byTrans) {
this->doneRead(callBack, pBuf, error, byTrans); });
This compiles fine, and runs as expected, 'doneRead' is called back from 'async_read_some'
so I have a similar call back in my own code:
client->asyncRead([=](string msg){this->newMsg(msg); });
This takes just a string, and asyncReads prototype is as follows
void ClientConnection::asyncRead(void(*callBack)(string))
But I get this compile error:
Server.cpp: In member function ‘void
Server::clientAccepted(std::shared_ptr,
const boost::system::error_code&)’:
Server.cpp:31:3: error: no matching
function for call to
‘ClientConnection::asyncRead(Server::clientAccepted(std::shared_ptr,
const
boost::system::error_code&)::)’
Server.cpp:31:3: note: candidate is:
ClientConnection.h:16:9: note: void
ClientConnection::asyncRead(void
(*)(std::string))
ClientConnection.h:16:9: note: no
known conversion for argument 1 from
‘Server::clientAccepted(std::shared_ptr,
const
boost::system::error_code&)::’
to ‘void (*)(std::string)’
How can this issue be resolved?
Your lambda captures this implicitly. A lambda that captures things cannot convert to a raw function pointer.
So you need to write asyncRead so it accepts the lambda function object directly, instead of letting it convert to a function pointer
template<typename CallbackType>
void ClientConnection::asyncRead(CallbackType callback);
Alternatively, if you don't want to write this as a template, you can use a polymorphic function object wrapper
void ClientConnection::asyncRead(std::function<void(string)> callBack);
I would also consider changing the callback's interface so it accepts the string by const reference (unless all the callback implementations inherently want to modify or save/move the passed string internally, which seem unlikely in your case).