Предоставляет ли C ++ 11, 14 или 17 способ получить только аргументы из decltype ()?

Этот вопрос очень похож на:Извлечь только список типов аргументов из decltype (someFunction)Msgstr «Я не уверен, что ответы там работают для того, что я намереваюсь. Я хотел бы иметь возможность создать шаблонную функцию, которая определяет тип ее аргументов времени выполнения на основе типа аргумента шаблона указателя на функцию (свистки).

Для примера использования, скажем, я хочу использовать прямой ввод-вывод C-файла POSIX, используя библиотеку shim, загруженную с LD_PRELOAD. Я мог бы написать отдельные обертки для fopen, fread, fwrite, fclose … Хотя, если бы все эти обертки делали подобные вещи, не было бы неплохо, если бы я мог определить шаблон, который фиксирует общее поведение?

Частичный пример НЕ использует шаблоны, которые демонстрируют, сколько шаблонов задействовано:

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 ...

}

Мы можем сохранить некоторый код, используя шаблонную функцию:

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);
}

Должен быть какой-то способ, которым мы можем избежать передачи всех этих избыточных типов в списке параметров шаблона. Что я хотел бы сделать, так это то, что я еще не нашел допустимый синтаксис (предполагается, что существует нечто, что я назову std :: arguments_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);
}

Есть ли правильный способ сделать это в C ++ 11, 14 или 17? Как, а если нет, то почему?

6

Решение

Вы используете частичную специализацию:

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) { /* ... */ }
};

Проблема заключается в том, что, поскольку вы не можете частично специализировать функции, вам нужно использовать шаблон класса — здесь Wrapper,

9

Другие решения

Вы можете использовать указатель на функцию для вывода типов возврата и аргументов:

#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

В вашем шаблонном решении Args можно вывести, так

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

достаточно.

1