This is probably a philosophical question, but I ran into the following problem:
If you define an std::function, and you don't initialize it correctly, your application will crash, like this:
typedef std::function<void(void)> MyFunctionType;
MyFunctionType myFunction;
myFunction();
If the function is passed as an argument, like this:
void DoSomething (MyFunctionType myFunction)
{
myFunction();
}
Then, of course, it also crashes. This means that I am forced to add checking code like this:
void DoSomething (MyFunctionType myFunction)
{
if (!myFunction) return;
myFunction();
}
Requiring these checks gives me a flash-back to the old C days, where you also had to check all pointer arguments explicitly:
void DoSomething (Car *car, Person *person)
{
if (!car) return; // In real applications, this would be an assert of course
if (!person) return; // In real applications, this would be an assert of course
...
}
Luckily, we can use references in C++, which prevents me from writing these checks (assuming that the caller didn't pass the contents of a nullptr to the function:
void DoSomething (Car &car, Person &person)
{
// I can assume that car and person are valid
}
So, why do std::function instances have a default constructor? Without default constructor you wouldn't have to add checks, just like for other, normal arguments of a function.
And in those 'rare' cases where you want to pass an 'optional' std::function, you can still pass a pointer to it (or use boost::optional).
True, but this is also true for other types. E.g. if I want my class to have an optional Person, then I make my data member a Person-pointer. Why not do the same for std::functions? What is so special about std::function that it can have an 'invalid' state?
It does not have an "invalid" state. It is no more invalid than this:
std::vector<int> aVector;
aVector[0] = 5;
What you have is an empty function, just like aVector is an empty vector. The object is in a very well-defined state: the state of not having data.
Now, let's consider your "pointer to function" suggestion:
void CallbackRegistrar(..., std::function<void()> *pFunc);
How do you have to call that? Well, here's one thing you cannot do:
void CallbackFunc();
CallbackRegistrar(..., CallbackFunc);
That's not allowed because CallbackFunc is a function, while the parameter type is a std::function<void()>*. Those two are not convertible, so the compiler will complain. So in order to do the call, you have to do this:
void CallbackFunc();
CallbackRegistrar(..., new std::function<void()>(CallbackFunc));
You have just introduced new into the picture. You have allocated a resource; who is going to be responsible for it? CallbackRegistrar? Obviously, you might want to use some kind of smart pointer, so you clutter the interface even more with:
void CallbackRegistrar(..., std::shared_ptr<std::function<void()>> pFunc);
That's a lot of API annoyance and cruft, just to pass a function around. The simplest way to avoid this is to allow std::function to be empty. Just like we allow std::vector to be empty. Just like we allow std::string to be empty. Just like we allow std::shared_ptr to be empty. And so on.
To put it simply: std::function contains a function. It is a holder for a callable type. Therefore, there is the possibility that it contains no callable type.
Actually, your application should not crash.
ยง 20.8.11.1 Class bad_function_call [func.wrap.badcall]
1/ An exception of type bad_function_call is thrown by function::operator() (20.8.11.2.4) when the function wrapper object has no target.
The behavior is perfectly specified.
One of the most common use cases for std::function is to register callbacks, to be called when certain conditions are met. Allowing for uninitialized instances makes it possible to register callbacks only when needed, otherwise you would be forced to always pass at least some sort of no-op function.
The answer is probably historical: std::function is meant as a replacement for function pointers, and function pointers had the capability to be NULL. So, when you want to offer easy compatibility to function pointers, you need to offer an invalid state.
The identifiable invalid state is not really necessary since, as you mentioned, boost::optional does that job just fine. So I'd say that std::function's are just there for the sake of history.
There are cases where you cannot initialize everything at construction (for example, when a parameter depends on the effect on another construction that in turn depends on the effect on the first ...).
In this cases, you have necessarily to break the loop, admitting an identifiable invalid state to be corrected later.
So you construct the first as "null", construct the second element, and reassign the first.
You can, actually, avoid checks, if -where a function is used- you grant that inside the constructor of the object that embeds it, you will always return after a valid reassignment.
In the same way that you can add a nullstate to a functor type that doesn't have one, you can wrap a functor with a class that does not admit a nullstate. The former requires adding state, the latter does not require new state (only a restriction). Thus, while i don't know the rationale of the std::function design, it supports the most lean & mean usage, no matter what you want.
Cheers & hth.,
You just use std::function for callbacks, you can use a simple template helper function that forwards its arguments to the handler if it is not empty:
template <typename Callback, typename... Ts>
void SendNotification(const Callback & callback, Ts&&... vs)
{
if (callback)
{
callback(std::forward<Ts>(vs)...);
}
}
And use it in the following way:
std::function<void(int, double>> myHandler;
...
SendNotification(myHandler, 42, 3.15);
Related
I am trying to interface with a library written in c, that uses this familiar pattern:
void some_c_handler(void(*func)(void*), void* data);
Now, I want to write a C++ wrapper for this function that looks like this:
void my_new_cpp_handler(std::function<void()>&& func)
{
void (*p)() = foo(func);
void* data = bar(func);
some_c_handler(p, data);
}
Both some_c_handler and my_new_cpp_handler are solving the same problem; they're taking in some kind of function along with some state. But the latter is preferred in that it abstracts much of the implementation details from the user, and allows for simply passing in a lambda object.
So my_new_cpp_handler should take the func parameter it is given, convert it to a function pointer and pass its state on to data.
I don't know enough about the standard, or the implementation of std::function to know if this is even a reasonable request. Can foo and bar exist?
To put it differently, what I want is to be able to pass a stateful function to a c callback handler without having to manually instantiate my own struct type to pass along with it. Obviously std::function has already done this for us, so I'd love to be able to separate the function pointer from the state somehow and pass it onto the c-style handler. Is this possible?
Is this possible?
No.
You can wrap a C-style callback into an std::function<>..., and the compiler will emit code to extract the data and the handler and call it. However, the exact code to do so will depend on the compiler, the ABI and the standard C++ library being used. You can't magically reconstruct that code given only the std::function wrapper.
Further, an arbitrary std::function... (or a lambda) may wrap code other than a call to C-style handler. It should be obvious that applying the "magically reconstructed" code to extract C-style handler from such an instance of std::function... can't possibly succeed.
P.S.
To put it differently, what I want is to be able to pass a stateful function to a c callback handler without having to manually instantiate my own struct type to pass along with it. Obviously std::function has already done this for us
So why don't you just use what std::function has already done for you:
void my_new_cpp_handler(std::function<void()>&& func)
{
func(); // calls some_c_handler(p, data) IFF that is what "func" encodes.
}
If you were to carefully review the documentation for this library, you will find that the
void some_c_handler(void(*func)(void*), void* data);
Invokes func, passing it the data argument.
This is a very common design pattern for C libraries that take a callback function. In addition to the callback function, they also take an additional opaque pointer that is not interpreted by the library, but is blindly forwarded to the func. In other words, the C library invokes
func(data);
You can use this from C++ code to pass an ordinary pointer to any class.
This includes std::function, too.
The trick is that in most situations it will be necessary to use new:
auto *pointer=new std::function< function_type >...
The end result is a pointer that can be passed to the C library, together with a pointer to a "trampoline function":
some_c_handler(&cpp_trampoline, reinterpret_cast<void *>(pointer));
And the trampoline recasts the opaque pointer:
void cpp_trampoline(void *pointer)
{
auto real_pointer=reinterpret_cast<std::function< ... >*>(pointer);
// At this point, you have a pointer to the std::function here.
// Do with it as you wish.
The only detail you will need to square away here is to figure out the correct scope for the dynamically-allocated function pointer, in order to avoid memory leaks.
You can make a wrapper function whose purpose is to simply execute the std::function callback.
void some_c_handler(void(*)(void*), void*) {}
void std_function_caller(void* fn) {
(*static_cast<std::function<void()>*>(fn))();
};
auto make_std_function_caller(std::function<void()>& fn) {
return std::make_pair(std_function_caller, static_cast<void*>(&fn));
}
void my_new_cpp_handler(std::function<void()>&& func) {
const auto p = make_std_function_caller(func);
some_c_handler(p.first, p.second);
}
According to this link, the std::function object has no accessible member that can provide raw access to the pointer. You should probably define a struct that contains a pointer to the function pointer and the object, and a constructor wrapper that stores the pointer's address to the struct before the construction of your std::struct, so as to assign the address stored in the pointer it points to to your C handler's parameter.
I am trying to interface with a library written in c, that uses this familiar pattern:
void some_c_handler(void(*func)(void*), void* data);
Now, I want to write a C++ wrapper for this function that looks like this:
void my_new_cpp_handler(std::function<void()>&& func)
{
void (*p)() = foo(func);
void* data = bar(func);
some_c_handler(p, data);
}
Both some_c_handler and my_new_cpp_handler are solving the same problem; they're taking in some kind of function along with some state. But the latter is preferred in that it abstracts much of the implementation details from the user, and allows for simply passing in a lambda object.
So my_new_cpp_handler should take the func parameter it is given, convert it to a function pointer and pass its state on to data.
I don't know enough about the standard, or the implementation of std::function to know if this is even a reasonable request. Can foo and bar exist?
To put it differently, what I want is to be able to pass a stateful function to a c callback handler without having to manually instantiate my own struct type to pass along with it. Obviously std::function has already done this for us, so I'd love to be able to separate the function pointer from the state somehow and pass it onto the c-style handler. Is this possible?
Is this possible?
No.
You can wrap a C-style callback into an std::function<>..., and the compiler will emit code to extract the data and the handler and call it. However, the exact code to do so will depend on the compiler, the ABI and the standard C++ library being used. You can't magically reconstruct that code given only the std::function wrapper.
Further, an arbitrary std::function... (or a lambda) may wrap code other than a call to C-style handler. It should be obvious that applying the "magically reconstructed" code to extract C-style handler from such an instance of std::function... can't possibly succeed.
P.S.
To put it differently, what I want is to be able to pass a stateful function to a c callback handler without having to manually instantiate my own struct type to pass along with it. Obviously std::function has already done this for us
So why don't you just use what std::function has already done for you:
void my_new_cpp_handler(std::function<void()>&& func)
{
func(); // calls some_c_handler(p, data) IFF that is what "func" encodes.
}
If you were to carefully review the documentation for this library, you will find that the
void some_c_handler(void(*func)(void*), void* data);
Invokes func, passing it the data argument.
This is a very common design pattern for C libraries that take a callback function. In addition to the callback function, they also take an additional opaque pointer that is not interpreted by the library, but is blindly forwarded to the func. In other words, the C library invokes
func(data);
You can use this from C++ code to pass an ordinary pointer to any class.
This includes std::function, too.
The trick is that in most situations it will be necessary to use new:
auto *pointer=new std::function< function_type >...
The end result is a pointer that can be passed to the C library, together with a pointer to a "trampoline function":
some_c_handler(&cpp_trampoline, reinterpret_cast<void *>(pointer));
And the trampoline recasts the opaque pointer:
void cpp_trampoline(void *pointer)
{
auto real_pointer=reinterpret_cast<std::function< ... >*>(pointer);
// At this point, you have a pointer to the std::function here.
// Do with it as you wish.
The only detail you will need to square away here is to figure out the correct scope for the dynamically-allocated function pointer, in order to avoid memory leaks.
You can make a wrapper function whose purpose is to simply execute the std::function callback.
void some_c_handler(void(*)(void*), void*) {}
void std_function_caller(void* fn) {
(*static_cast<std::function<void()>*>(fn))();
};
auto make_std_function_caller(std::function<void()>& fn) {
return std::make_pair(std_function_caller, static_cast<void*>(&fn));
}
void my_new_cpp_handler(std::function<void()>&& func) {
const auto p = make_std_function_caller(func);
some_c_handler(p.first, p.second);
}
According to this link, the std::function object has no accessible member that can provide raw access to the pointer. You should probably define a struct that contains a pointer to the function pointer and the object, and a constructor wrapper that stores the pointer's address to the struct before the construction of your std::struct, so as to assign the address stored in the pointer it points to to your C handler's parameter.
I'm trying to make a function that accepts a shared pointer to some functor. With manually crafted functors there're no problems, but with lambda there are. I know that I can't use decltype with lambda - every new lambda declaration creates a new type. Right now I'm writing:
auto lambda = [](int a, float b)->int
{
return 42;
};
using LambdaType = decltype(lambda);
shared_ptr<LambdaType> ptr{ new LambdaType{ lambda } };
It works, but looks ugly. Moreover there's a copy constructor call! Is there any way to simplify?
You could use std::function as type.
Lambdas are merely auto written invokable objects to make simple code simple. It you want something beyond their default automatic storage behavior, write the type they write yourself.
It is illegal to have a lambda type in an unevaluated context. In an evaluated context, it creates a lambda in automatic storage. You want it on the free store. This requires at least logically a copy.
A horrible hack involving violating the unevaluated context rule, sizeof/alignof, aligned_storage_t, placement new, possibly unbounded compile time recursion (or maybe one with a static_assert), returning pointers to local variables, and the aliasing constructor of shared ptr, and requiring callers to write insane code might avoid calling the copy/move. But it is a bad idea, and simply using invokable objects is easier.
Of course, accepting the copy/move makes it trivial. But at that point, just use std::function unless you need something like varargs.
You state you do not want to force users to use std::function; but std::function would implicitly convert a compatible lambda into itself.
If you are willing to accept a copy, we can do this:
template<class T>
std::shared_ptr<std::decay_t<T>>
auto_shared( T&& t ) {
return std::make_shared<std::decay_t<T>>(std::forward<T>(t));
}
then auto ptr = auto_shared( [x=0]()mutable{ return x++; } ); is a non-type-erased shared pointer to a counting lambda. The lambda is copied (well, moved) into the shared storage.
If you want to avoid that copy, the client can write a manual function object and call make_shared<X>(ctor_args) on it.
There is no reasonable way to separate a lambdas type from its construction in C++ at this point.
if you catch something in lambda, it becomes algorithmically same as std::function, so use it freely. Also, std::function implements captured values memory management, so using std::shared_ptr on top of it is not required.
If you catch nothing, lambda is convertible to simple function pointer:
int(*ptr)(int,int) = [](int a, int b) -> int {
return a+b;
};
Functions are allocated statically and definitely shouldn't be deleted. So, you don't actually need std::shared_ptr
Is it possible to force C++ to construct an object in the scope of a calling function? What I mean is to explicitly do what an return value optimization (RVO) does.
I have some container classes which are in a chain of derivation. Since the classes are constructed with stack data, they can't be returned, so I disabled the copy constructor and assignment operators. For each class, I am providing an iterator. The constructor of each iterator has only one argument: a pointer to the container class. To get the iterator, I want to use this function:
BindPackIterator BindPack.begin(void)
{
return BindPackIterator(this);
}
in this context:
for (auto i=bindpack.begin(); !i.end(); ++i) { i.run(); }
The compiler issues errors, complaining about not being able to copy the BindPackIterator object. Remember, I disabled them.
What I want to happen is for the BindPackIterator to be instantiated in the calling function's scope to avoid either a copy or move operation.
In this particular case, I know I can do a workaround, changing the begin function to return a BindPack pointer,
for(BindPackIterator i=bindpack.begin(); !i.end(); ++i) { i.run(); }
and I've experimented a bit, without success, with decltype and this construction:
auto BindPack::begin(void) -> BindPackIterator
{
return BindPackIterator(this);
}
This is just the example with which I'm currently frustrated. There have been other projects where the obvious solution is for the function to instantiate an object in the calling function's scope. The move constructor (foo&&) helps in some cases, but for objects with many data members, even that can be inefficient. Is there a design pattern that allows object construction/instantiation in the caller's scope?
Putting n.m.'s comment into code, write a constructor for BindPackIterator that takes a BindPack and initializes the iterator in the "begin" state. e.g:
BindPackIterator(BindPack* pack) : pack(pack), pos(0){ }
That you can use in your for loop:
BindPack pack;
for(BindPackIterator i(&pack); !i.end(); ++i){
i.run();
}
Live demo
Is it fair to say that the answer is "No," it is not possible to construct a returned object in the calling function's scope? Or in other words, you can't explicitly tell the compiler to use RVO.
To be sure, it is a dangerous possibility: stack memory used to construct the object while available in the called function will not be valid in the calling function, even though the values might remain untouched in the abandoned stack frame. This would result in unpredictable behavior.
Upon further consideration, while summing up at the end of this response, I realized that the compiler may not be able to accurately predict the necessary stack size for objects created in the calling function and initialized in a called function, and it would not be possible to dynamically expand the stack frame if the execution had passed to another function. These considerations make my whole idea impossible.
That said, I want to address the workarounds that solve my iterator example.
I had to abandon the idea of using auto like this:
for (auto i=bindpack.begin(); !i.end(); ++i)
Having abandoned auto, and realizing that it's more sensible to explicitly name the variable anyway (if the iterator is different enough to require a new class, it's better to name it to avoid confusion) , I am using this constructor:
BindPackIterator(BindPack &ref) : m_ref_pack(ref), m_index(0) { }
in order to be able to write:
for (BindPackIterator i=bindpack; !i.end(); ++i)
preferring to initialize with an assignment. I used to do this when I was last heavily using C++ in the late 1990's, but it's not been working for me recently. The compiler would ask for a copy operator I didn't want to define for reasons stated above. Now I think that problem was due to my collection of constructors and assignment operators I define to pass the -Weffc++ test. Using simplified classes for this example allowed it to work.
Another workaround for an object more complicated than an iterator might be to use a tuple for the constructor argument for objects that need multiple variables to initialize. There could be a casting operator that returns the necessary tuple from the class that initializes the object.
The constructor could look like:
FancyObject(BigHairyTuple val) : m_data1(get<0>(val)), m_data2(get<1>(val), etc
and the contributing object would define this:
class Foo
{
...
operator BigHairyTuple(void) {
return BigHairyTuple(val1, val2, ...);
}
};
to allow:
FancyObject fo = foo;
I haven't tested this specific example, but I'm working with something similar and it seems likely to work, with some possible minor refinements.
Let's say I have a function which takes an std::function:
void callFunction(std::function<void()> x)
{
x();
}
Should I pass x by const-reference instead?:
void callFunction(const std::function<void()>& x)
{
x();
}
Does the answer to this question change depending on what the function does with it? For example if it is a class member function or constructor which stores or initializes the std::function into a member variable.
If you want performance, pass by value if you are storing it.
Suppose you have a function called "run this in the UI thread".
std::future<void> run_in_ui_thread( std::function<void()> )
which runs some code in the "ui" thread, then signals the future when done. (Useful in UI frameworks where the UI thread is where you are supposed to mess with UI elements)
We have two signatures we are considering:
std::future<void> run_in_ui_thread( std::function<void()> ) // (A)
std::future<void> run_in_ui_thread( std::function<void()> const& ) // (B)
Now, we are likely to use these as follows:
run_in_ui_thread( [=]{
// code goes here
} ).wait();
which will create an anonymous closure (a lambda), construct a std::function out of it, pass it to the run_in_ui_thread function, then wait for it to finish running in the main thread.
In case (A), the std::function is directly constructed from our lambda, which is then used within the run_in_ui_thread. The lambda is moved into the std::function, so any movable state is efficiently carried into it.
In the second case, a temporary std::function is created, the lambda is moved into it, then that temporary std::function is used by reference within the run_in_ui_thread.
So far, so good -- the two of them perform identically. Except the run_in_ui_thread is going to make a copy of its function argument to send to the ui thread to execute! (it will return before it is done with it, so it cannot just use a reference to it). For case (A), we simply move the std::function into its long-term storage. In case (B), we are forced to copy the std::function.
That store makes passing by value more optimal. If there is any possibility you are storing a copy of the std::function, pass by value. Otherwise, either way is roughly equivalent: the only downside to by-value is if you are taking the same bulky std::function and having one sub method after another use it. Barring that, a move will be as efficient as a const&.
Now, there are some other differences between the two that mostly kick in if we have persistent state within the std::function.
Assume that the std::function stores some object with a operator() const, but it also has some mutable data members which it modifies (how rude!).
In the std::function<> const& case, the mutable data members modified will propagate out of the function call. In the std::function<> case, they won't.
This is a relatively strange corner case.
You want to treat std::function like you would any other possibly heavy-weight, cheaply movable type. Moving is cheap, copying can be expensive.
If you're worried about performance, and you aren't defining a virtual member function, then you most likely should not be using std::function at all.
Making the functor type a template parameter permits greater optimization than std::function, including inlining the functor logic. The effect of these optimizations is likely to greatly outweigh the copy-vs-indirection concerns about how to pass std::function.
Faster:
template<typename Functor>
void callFunction(Functor&& x)
{
x();
}
As usual in C++11, passing by value/reference/const-reference depends on what you do with your argument. std::function is no different.
Passing by value allows you to move the argument into a variable (typically a member variable of a class):
struct Foo {
Foo(Object o) : m_o(std::move(o)) {}
Object m_o;
};
When you know your function will move its argument, this is the best solution, this way your users can control how they call your function:
Foo f1{Object()}; // move the temporary, followed by a move in the constructor
Foo f2{some_object}; // copy the object, followed by a move in the constructor
Foo f3{std::move(some_object)}; // move the object, followed by a move in the constructor
I believe you already know the semantics of (non)const-references so I won't belabor the point. If you need me to add more explanations about this, just ask and I'll update.