This question is very similar to: " Extract only a list of argument types from decltype (someFunction) ." I'm not sure if the answers there work for what I intend. I would like to be able to create a template function that displays the type of the runtime arguments based on the argument type of the function pointer template (whistles).
In an example use case, let's say I want to use direct input / output of C POSIX files using the pad library loaded by LD_PRELOAD. I could write separate wrappers for fopen, fread, fwrite, fclose ... If all of these wrappers did similar things, would it be nice if I could define a pattern that reflects the general behavior?
A partial example is NOT to use patterns that demonstrate how many patterns are involved:
extern "C" { FILE *(*real_fopen)(const char *, const char *) = NULL; FILE *fopen(const char *path, const char *mode) { FILE *returned_file; if (real_fopen == NULL) { real_fopen = ((FILE *)(const char *, const char *))dlsym("fopen", RTLD_NEXT); } ... do pre-call instrumentation ... returned_file = real_fopen(path, mode); ... do post-call instrumentation ... return returned_file; } int (*real_fclose)(FILE *) = NULL; int fclose(FILE *fp) { int retval; if (real_fclose == NULL) { real_fclose = ((int)(FILE *))dlsym("fclose", RTLD_NEXT); } ... do pre-call instrumentation ... retval = real_fclose(path, mode); ... do post-call instrumentation ... return retval; } ... additional definitions following the same general idea ... }
We can save some code using the template function variable:
template <typename func_ptr_type, func_ptr_type real_func_ptr, const char *dl_name, typename... Args> std::result_of<func_type> wrap_func(Args... args) { std::result_of<func_type> retval; if (real_func_ptr == NULL) { real_func_ptr = (func_ptr_type)dlsym(dl_name, RTLD_NEXT); } ... do pre-call instrumentation ... retval = real_func_ptr(args...); ... do post-call instrumentation ... return retval; } FILE *(*real_fopen)(const char *, const char *) = NULL; FILE *fopen(const char *path, const char *mode) { return wrap_func<decltype(real_fopen), real_fopen, "fopen", const char *, const char *>(path, mode); } int (*real_fclose)(FILE *) = NULL; int fclose(FILE *fp) { return wrap_func<decltype(real_fclose), real_fclose, "fclose", FILE *>(fp); }
There must be some way we can avoid passing all of these redundant types in the template parameter list. What I would like to do has not yet found the correct syntax (assumes the existence of something that I call std :: arguments_of, similar to the opposite of std :: result_of):
template <typename func_ptr_type, func_ptr_type real_func_ptr, const char *dl_name, std::arguments_of(func_ptr_type)> std::result_of<func_type> wrap_func(std::arguments_of(func_ptr_type)... args) { std::result_of<func_type> retval; if (real_func_ptr == NULL) { real_func_ptr = (func_ptr_type)dlsym(dl_name, RTLD_NEXT); } ... do pre-call instrumentation ... retval = real_func_ptr(args...); ... do post-call instrumentation ... return retval; } FILE *(*real_fopen)(const char *, const char *) = NULL; FILE *fopen(const char *path, const char *mode) { return wrap_func<decltype(real_fopen), real_fopen, "fopen">(path, mode); } int (*real_fclose)(FILE *) = NULL; int fclose(FILE *fp) { return wrap_func<decltype(real_fclose), real_fclose, "fclose">(fp); }
Is there a valid way to do this in C ++ 11, 14 or 17? How, and if not, why not?