Please consider the following:
typedef int (*callback_function)(int a, int b);
class receiving_callbacks_class
{
public:
static register_callback(int iterator, callback_function fn)
{
function_list[iterator] = fn;
}
private:
static callback_function function_list[10];
}
This function_list is used by a C library, so it can do call backs on certain events.
I now would like to add a routine to every callback that gets registered via this function. So that it gets called like this:
default_routine();
fn();
I tried doing it with templates, but I could not find a way to do that inside the register_callback function. Every way to do it with templates meant wrapping the function to register before calling register_callback. I would like to contain this inside this particular class.
This differs from How to add standard routine to every function in array of function pointers? by adding the requirement that no changes can be made where register_callback is called; all changes must be within receiving_callbacks_class.
This is for an embedded system where I don't have the freedom to use std. All functions passed to the register_class function will be static.
Is this possible?
First, I would like to add a preamble explaining why this is difficult in general. There is a problem involving the amount of information being stored in the C library. Other C callbacks systems store two pieces of information per callback: the address of the function to call and arbitrary data cast to void*. The function is required to accept a void* argument in addition to the arguments required by the nature of the callback. This "extra" argument receives the arbitrary data. Casting this back to its original type allows access to as much extra data as needed; it could be null if no extra data is needed. (In this case, it would be cast back to callback_function.)
In the current context, however, the only information stored in the C library is the address of a function to call. This information must be different if different callbacks are to be invoked, hence there must be different functions. The requirement that the call site not be changed means that the different functions need to be provided by receiving_callbacks_class, yet these functions need to adapt when new callbacks are written by users of receiving_callbacks_class.
I can think of four main techniques for generating multiple similar functions in C++, but one of them uses macros, so let's call it three: lambdas, templates, and copy-paste. A lambda that captures the address of the real callback is no longer convertible to a function pointer, so no longer usable with the C library. A template would use the address of the real callback as the template parameter, which means that address would have to be a compile-time constant. However, C++ does not provide a way to require that a function argument be a compile-time constant, making the approach unsuitable for use inside register_callback(). That leaves copy-paste, which normally is a pain, but might be acceptable when the number of callbacks is as small as 10.
I can base an approach on the definition of function_list. There is a smallish limit on the number of callbacks passed to the C library and they can be invoked in constant time, given their index. This approach might be less appealing if the array is replaced by a container that does not support indexed access. It definitely becomes less appealing as the size of the container increases. It might be unusable if there is not a compile-time limit on the size of the container.
To receiving_callbacks_class I might add two pieces of static data: a second array of function pointers, and a size for both of the arrays.
class receiving_callbacks_class
{
public:
// Always use a symbolic constant when a magic number is needed more than once.
static constexpr unsigned MAX_CALLBACKS = 10;
// Looks the same (but with a return type), and called the same as before.
static void register_callback(int iterator, callback_function fn)
{
function_list[iterator] = fn;
}
private:
// Old array using the new symbolic constant
static callback_function function_list[MAX_CALLBACKS];
// A new array, probably should be `const`.
static const callback_function wrapper_list[MAX_CALLBACKS];
};
The new array is for storing pointers to wrapper functions, functions that will call default_routine() followed by the real callback. This array, not the old one, is what should be given to the C library. It still needs to be initialized, though. The initialization of the new array is where copy-paste comes in. I leave it to the reader to decide how large they would let MAX_CALLBACKS get before this is considered unmanageable. Personally, I found the copy-paste to be reasonable when the size is 10.
// Initialize the new array
const callback_function receiving_callbacks_class::wrapper_list[MAX_CALLBACKS] = {
[](int a, int b) -> int { default_routine(); return function_list[0](a, b); },
[](int a, int b) -> int { default_routine(); return function_list[1](a, b); },
[](int a, int b) -> int { default_routine(); return function_list[2](a, b); },
[](int a, int b) -> int { default_routine(); return function_list[3](a, b); },
[](int a, int b) -> int { default_routine(); return function_list[4](a, b); },
[](int a, int b) -> int { default_routine(); return function_list[5](a, b); },
[](int a, int b) -> int { default_routine(); return function_list[6](a, b); },
[](int a, int b) -> int { default_routine(); return function_list[7](a, b); },
[](int a, int b) -> int { default_routine(); return function_list[8](a, b); },
[](int a, int b) -> int { default_routine(); return function_list[9](a, b); },
};
It might be appropriate to add a null check on the appropriate function_list entry; I do not know how you handle having fewer than 10 callbacks.
Note that these lambdas are non-capturing, so they do convert to function pointers. They can be non-capturing only because their number is fixed at compile-time.
The last piece to change is what I mentioned before. The call into the C library would use the new array instead of the old. This was not included in the sample code, so I'll devise a name and parameter list.
//c_library(function_list, 10); // <-- replace this
c_library(wrapper_list, MAX_CALLBACKS); // <-- with this
Not my preferred setup, but it does meet the restrictions in the question.
Related
I have two functions with the same name but different return types. I want to run the function based on their third parameter. If the third parameter is true I want to run the first and If the parameter is false to run the second function. I was trying different things on my own because I couldn't find information online and I wasn't sure how is this called. Here is what I tried to do:
static int function(int a, int b, const bool=true);
static std::string function(int a, int b, const bool=false);
I would be grateful if someone can explain how to do this or at least give me a link to some information.
This solution is not about having two different functions but if you wanted the function to return a different type depending on the bool value using boost::any.
boost::any function(int a, int b, const bool c) {
std::string str = "Hello world!";
int num = 10;
if ( c ) {
return boost::any(num);
} else {
return boost::any(str);
}
}
This would use the third parameter in the function in order to decide which return you should do. Depending on how big function is this might be a worse solution but if you really wanted to use a boolean as a parameter I believe this should work.
Docs: Boost
Related question to this answer: Function which returns an unknown type
You can create a function template and add specializations for the different return types. Then you could use the bool argument as a template parameter:
template<bool>
auto function(int, int);
template<>
auto function<true>(int a, int b)
{
// ...
return int{};
}
template<>
auto function<false>(int a, int b)
{
// ...
return std::string{};
}
The functions would then be called like this:
int a = function<true>(1,2);
std::string b = function<false>(1,2);
Here's a demo.
Note the important caveat that the bool parameter must be known at compile time, and can't be a run time argument.
While this technique will work, do be aware that this will confuse a lot of c++ programmers. They usually expect a function to always return a particular type.
More relevant to your question; this is not actually going to make the code much more readable. Instead, having separate named functions is probably a more readable approach:
int int_function(int a, int b);
std::string str_function(int a, int b);
which could be called like this:
int a = int_function(1,2);
std::string b = str_function(1,2);
I have a member function with two arguments. Both are pointers to complex objects. When called, the function performs some non-trivial computation and then returns an integer. Like this:
struct Fooer {
int foo(const A* a, const B* b);
};
The returned integer is always the same if foo() is given the same two arguments. This function is pretty heavily used, so it would make sense to memoize its result. Normally, some lookup table with the key being the pair of pointers would suffice. However, I'm in the unique position where I know all the call sites and I know that any given call site will always use the same pair of parameters during execution. This could greatly speed up memoization if only I could pass in a third parameter, a unique integer that is basically the cache hint:
struct Fooer {
int foo(const A* a, const B* b, int pos) {
if (cached_[pos] > 0) return cached_[pos];
cached_[pos] = /* Heavy computation. */ + 1;
return cached_[pos];
}
std::vector<int> cached_;
};
What I'm looking for is a mechanism to easily generate this 'cache hint'. But nothing comes to mind. For now, I'm manually adding this parameter to the call sites of foo(), but it's obviously ugly and fragile. The function is really heavily used so it's worth this kind of optimization, in case you're wondering.
More generally, I'd like to have some kind of 'thunk' at each call site that performs the heavy lifting the first time is called, then just returns the pre-computed integer.
Note that foo() is a member function so that different instances of Fooer should have different caches.
Would this approach help you?
struct Fooer {
using CacheMap = std::map<std::pair<const A*, const B*>, int>;
std::map<int, CacheMap> lineCache;
int foo(const A* a, const B* b, int line) {
const auto key = std::make_pair(a,b);
if (linecache.count(line) > 0) {
CacheMap& cacheMap = lineCache[line];
if(cacheMap.count(key)) return cacheMap[key];
}
lineCache[line][key] = /* Heavy computation. */ + 1;
return cacheMap[key];
}
};
// Calling
foo(a, b, __LINE__)
See _ReturnAddress or any alternatives for yours compiler. Maybe you can use it in your project. Obviously, if it work for you, than just create map caller-result.
Suppose I want to implement a simple abstraction over pthreads.
(or any C API that takes function pointers for callbacks or threads).
Like std::thread, I want the interface to be able to take function objects in general.
How do I bridge the gap in a way that works for all cases?
(That includes binds, lambda functions, etc.)
I know about the std::function::target but afaik, it does not do what I need.
If the API takes functions with a void* for user data as, e.g., pthread_create() does, you'd pass a pointer to the function as user data, call a trampoline which casts the user data to your function type, and calls the function. For example:
#include <functional>
#include <pthread.h>
extern "C" void* trampoline(void* userData) {
return (*static_cast<std::function<void*()>*>(userData))();
}
void* start() {
// ...
return 0;
}
int main() {
pthread_t thread;
std::function<void*()> entry(start);
pthread_create(&thread, 0, &trampoline, &entry);
// ...
}
The immediate implication is, however, that the function object life-time isn't easily controlled. In the example above the std::function<void*()> object happens to live long enough but it isn't always as easy.
If the function you try to call doesn't have a user data argument, you are pretty much out of luck. You might get away with using global objects but it is almost certainly a rather fragile approach.
A lambda function can be used anywhere that takes regular function pointers. In other words, it can be used wherever you would use regular functions/pointers to functions..
Example: https://ideone.com/4CJjlL
#include <iostream>
void voidfunc(void (*func_ptr)(void))
{
func_ptr();
}
void funcwithargs(void (*func_ptr)(int, char, std::string), int a, char b, std::string c)
{
func_ptr(a, b, c);
}
int main()
{
auto vf = []{std::cout<<"Called void func..\n";};
auto vfwa = [](int a, char b, std::string c) {std::cout<<"Called func with args with: "<<a<<b<<" "<<c<<"\n";};
voidfunc(vf);
funcwithargs(vfwa, 10, 'x', " + 3");
return 0;
}
Likewise, you can use std::function instead of the function pointer..
I am assuming that the function already has a return value so that cannot be added.
What I came up with to solve this problem is to add extra pointer parameters which default to nullptr.
Before:
bool fun(double a, std::vector<std::randomexample> const & b)
After:
bool fun(double a, std::vector<std::randomexample> const & b, int* extraoutput = nullptr)
and use it like this
if(extraoutput)
*extraoutput = whatever;
But that's just what I came up with.
I would like to know if there is a better way to do this. Note that "whatever" is already in the function.
If for some reason you need binary as well as (mostly) source compatibility[*]:
Before:
bool fun(double a, std::vector<std::randomexample> const & b) {
// do stuff
return true;
}
After:
bool fun(double a, std::vector<std::randomexample> const & b, int* extraoutput) {
// do stuff
if(extraoutput)
*extraoutput = whatever;
return true;
}
bool fun(double a, std::vector<std::randomexample> const & b) {
return fun(a, b, nullptr);
}
If you don't want function overloading (for example if fun is part of an extern "C" interface), then you don't actually have to call the new function fun. It could just as well be fun2.
[*] As AndreyT points out, the source compatibility of your solution is limited. Calls to your old function will call your new function fine, but some other things that you might do with the old function will not work fine (since you have changed its type).
There's actually a source incompatibility in my code too. void(*foo)() = (void(*)()) fun; is allowed before the overload is added, but afterwards it's ambiguous. If you want to support code that does that, then that's a second reason not to want function overloading.
Normally, I add a method with the extra parameter, and call that one with a default value from the former method:
//foo v1
void foo( S s ) {
... stuff with s;
};
//codeA_v1:
S s;
foo(s);
//codeB_v1
S s2;
foo(s2);
Then, I add a method with an extra parameter:
void foo(S s){ foo(s, default_value_for_T); }
void foo(S s, T t){
... stuff with s and t
}
//codeA_v1 == codeA_v2
S s;
foo(s);
//codeB_v2
S s;
T t;
foo(s,t);
This is an extended comment. As alredy suggested by the others, you'd better overload the function in order to provide both source and binary compatibility. The reason to do so is that by introducing a change in the function signature, you also change the mangled symbol name, e.g. from _Z3fundRKSt6vectorISt13randomexampleSaIS0_EE to _Z3fundRKSt6vectorISt13randomexampleSaIS0_EEPi. This would break binary compatibility with all other objects that call fun() by its old mangled name. If fun() is part of a dynamically linked library, it will break all existing binaries that link against it since the dynamic linker would no longer be able to resolve the _Z3fundRKSt6vectorISt13randomexampleSaIS0_EE symbol reference. If you go with the overloaded function version, the old mangled symbol would still exist and binary compatibility would be retained.
As stated by others, this will be your final product.
bool fun(double a, std::vector<std::randomexample> const & b){
return fun(a,b,0);
}
bool fun(double a, std::vector<std::randomexample> const & b, int* extraoutput = 0){
// have fun!
if(extraoutput) *extraoutput = whatever;
return true;
}
You can try to implement genernic Observer pattern.
Here is a like:
http://sourcemaking.com/design_patterns/observer
It will be better for the future when you will want to add more parameters. If you cant derive then passing as a parameter will be solution too.
As i understand you have to do it in this function, otherwise yes overload is a good solution.
It doesnt break a binary compability otherwise to other solution.
I have a function that requires a function pointer as argument:
int func(int a, int (*b)(int, int))
{
return b(a,1);
}
Now I want to use a certain function that has three arguments in this function:
int c(int, int, int)
{
// ...
}
How can I bind the first argument of c so that I'm able to do:
int i = func(10, c_bound);
I've been looking at std::bind1st but I cannot seem to figure it out. It doesn't return a function pointer right? I have full freedom to adapt func so any changes of approach are possible. Althoug I would like for the user of my code to be able to define their own c...
note that the above is a ferocious simplification of the actual functions I'm using.
The project sadly requires C++98.
You can't do that. You would have to modify func to take a function-object first. Something like:
int func( int a, std::function< int(int, int) > b )
{
return b( a, rand() );
}
In fact, there is no need for b to be an std::function, it could be templated instead:
template< typename T >
int func( int a, T b )
{
return b( a, rand() );
}
but I would stick with the std::function version for clarity and somewhat less convoluted compiler output on errors.
Then you would be able to do something like:
int i = func( 10, std::bind( &c, _1, _2, some-value ) );
Note all this is C++11, but you can do it in C++03 using Boost.
Well, if you know at compile time, what you have to bind c with, you could define a new function
int c_bound(int a, int b) {
return c(a,b,some_value);
}
That's obviously not a generic solution but might solve your current problem. Otherwise K-ballo's solution seems to be the only easy generic one. However, that requires you to be able to change the signature of func. If you really have an API that you can't touch the signature, and you still need to bind an argument AND if the above solution doesn't solve your specific case: (Caution, overkill ahead) I've always wanted to use an LLVM based solution to compile a function at runtime and pass its address in such situations.
You would be unable to use a 3 argument function as a 2 argument function; Mainly because there is no real way to determine what the 3rd parameter would do.
While the above answer would work, here is another option:
If one of the parameters for c(), in use within func, is constant, you could write a wrapper function for c(int, int, int):
int d(int a, int b)
{
return c(a, b, 0); //use a constant parameter
}
or, if you can determine the 3rd parameter from the two given parameters, you can also try:
int e(int a, int b)
{
int extra = 0;
///Determine extra from a, and b
return c(a, b, c);
}