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).
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.
I am trying to write a wrapper on top of winapi. I want to wrap functions that accept pointers for callback functions.
As an example, consider this:
// The unsafe callback type the FFI function accepts
type UnsafeCallback = unsafe extern "system" fn(exception_info: *mut ExceptionInfo) -> u32;
// The safe callback type my function should accept
type SafeCallback = fn(exception_info: &ConvertedExceptionInfo) -> u32;
The functions that will be used:
// The function exposed by winapi
unsafe extern "system" fn SetExceptionHandler(handler: UnsafeCallback);
// The function I want to expose in my library
fn SetExceptionHandler(handler: SafeCallback);
I want to create a wrapping function that looks like this:
unsafe extern "system" fn(exception_info: *mut ExceptionInfo) -> u32 {
let result = panic::catch_unwind(|| {
// Convert ExceptionInfo into ConvertedExceptionInfo. I know this is undefined behavior, but its only here
// to demonstrate program flow
let converted_exception_info: ConvertedExceptionInfo = (*exception_info).into();
// Call the corresponding safe function (as to how we get the function pointer here, that's
// the whole question)
return safe_callback(&converted_exception_info);
});
return match result {
Ok(val) => val,
Err(_) => _
};
}
I can think of two possibilities to create this wrapping function:
Creating a wrapping function at runtime
Create a closure or similar construct inside the safe
SetExceptionHandler method.
I have no idea how to get the closure across the FFI boundary.
Exposing a conversion macro and generating the function at compile time
Edit the SetExceptionHandler function to accept the UnsafeCallback
type.
Then I could create a macro that generates the wrapping function at compile time and expose this macro to the user.
I would have to expose unsafe extern parameters again, so it is not
how I would prefer to do it.
I have no idea how to structure such a macro or if this is even possible.
Is my first idea possible and feasible? If so, how could this be done?
If not, is writing a macro like the second idea possible and feasible? If so, how could this be done?
Based on
How do I create a Rust callback function to pass to a FFI function?
How do I convert a Rust closure to a C-style callback?
How do I pass a closure through raw pointers as an argument to a C function?
I get the impression that my first idea is probably not possible with the exception of something called trampolining.
Is trampolining possible in safe Rust and in this situation?
After much searching, i have found a blog post that explains a nice solution for the problem of wrapping callbacks. Article here
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.
I have a legacy template function I'm trying to call that has a slew of specializations for function pointers with different numbers of arguments. I'm writing a new template function of my own that take some arbitrary kind of non-capturing lambda and needs to pass it to the other library. If I do this directly, then the template resolution fails. If however I explicitly cast it to be related function pointer type, things work.
The problem then is how to make my template code get that function pointer type from the lambda's type or force the explicit conversion without explicitly referencing the type.
Just use unary-plus to convert a lambda to a function pointer, as in:
auto* f = +[]{ std::cout << "Hello, world!\n"; }; // f is of type void (*)()
I have recently wrapped my mind around the C++0x's concepts of glvalues, xvalues and prvalues, as well as the rvalue references. However, there's one thing which still eludes me:
What is "an rvalue reference to function type"? It is literally mentioned many times in the drafts. Why was such a concept introduced? What are the uses for it?
I hate to be circular, but an rvalue reference to function type is an rvalue reference to function type. There is such a thing as a function type, e.g. void (). And you can form an rvalue reference to it.
In terms of the classification system introduced by N3055, it is an xvalue.
Its uses are rare and obscure, but it is not useless. Consider for example:
void f() {}
...
auto x = std::ref(f);
x has type:
std::reference_wrapper<void ()>
And if you look at the synopsis for reference_wrapper it includes:
reference_wrapper(T&) noexcept;
reference_wrapper(T&&) = delete; // do not bind to temporary objects
In this example T is the function type void (). And so the second declaration forms an rvalue reference to function type for the purpose of ensuring that reference_wrapper can't be constructed with an rvalue argument. Not even if T is const.
If it were not legal to form an rvalue reference to function, then this protection would result in a compile time error even if we did not pass an rvalue T to the constructor.
In the old c++ standard the following is forbidden:
int foo();
void bar(int& value);
int main()
{
bar(foo());
}
because the return type of foo() is an rvalue and is passed by reference to bar().
This was allowed though with Microsoft extensions enabled in visual c++ since (i think) 2005.
Possible workarounds without c++0x (or msvc) would be declaring
void bar(const int& value);
or using a temp-variable, storing the return-value of foo() and passing the variable (as reference) to bar():
int main()
{
int temp = foo();
bar(temp);
}