Does C ++ 11, 14, or 17 provide a way to get only arguments from the decltype () method?

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?

+6
source share
3 answers

You are using partial specialization:

 template <typename func_ptr_type, func_ptr_type real_func_ptr, const char *dl_name> struct Wrapper; template <typename Ret, typename... Args, Ret (*real_func_ptr)(Args...), const char *dl_name> struct Wrapper<Ret(*)(Args...), real_func_ptr, dl_name> { static Ret func(Args... args) { /* ... */ } }; 

The wrinkle is that since you cannot partially specialize functions, you need to use a class template - here is Wrapper .

+9
source

You can use the function pointer to output return types and arguments:

 #include <iostream> FILE *fake_fopen(const char *path, const char *mode) { std::cout << "Library Function: " << path << " " << mode << "\n"; return nullptr; } template <typename Result, typename... Arguments> Result dl_wrap( const char* dl_name, Result (*&function)(Arguments...), // Reference to function pointer Arguments... arguments) { function = (Result (*)(Arguments...))fake_fopen; //dlsym return function(arguments ...); } FILE *(*real_fopen)(const char *, const char *) = nullptr; FILE *fopen(const char *path, const char *mode) { return dl_wrap("fopen", real_fopen, path, mode); } int main(int argc, char* argv[]) { fopen("Hello", "World"); } 
+3
source

Args can be inferred in your solution, therefore

 return wrap_func<decltype(real_fopen), real_fopen, "fopen">(path, mode); 

.

+1
source

Source: https://habr.com/ru/post/981771/


All Articles