2015-01-30 5 views
6

Этот вопрос очень похож на: «Extract just the argument type list from decltype(someFunction)». Я не уверен, что ответы там работают на то, что я намереваюсь. Я хотел бы иметь возможность создать функцию шаблона, которая выводит тип аргументов времени выполнения на основе типа аргумента шаблона указателя функции (whistles).Предоставляет ли C++ 11, 14 или 17 способ получить только аргументы из decltype()?

Для примера используйте случай, скажем, я хочу использовать прямое C/POSIX-файл ввода-вывода, используя библиотеку прокладок, загруженную 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 ... 

} 

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

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

Там же должен быть каким-то образом мы можем избежать передавая все эти избыточные типы в списке параметров шаблона. То, что я хотел бы сделать, что я не нашел правильный синтаксис еще (предполагает существование чего-то я позвоню станд :: arguments_of, что вроде как противоположность станд :: 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? Как, а если нет, почему бы и нет?

+0

Есть несколько других проблем с вашим дизайном. Строковый литерал нельзя использовать в качестве аргумента шаблона, а также не константное выражение, например 'real_fclose'. И вы не можете назначить параметр шаблона. –

+0

Я мог видеть, где было бы более идиоматично иметь real_func_ptr в качестве параметра для wrap_func функции, а не шаблона. Кажется, он работает так, как я понял, с Intel C++ 15 и -std = C++ 11. Является ли ICPC 15 просто разрешающим мне правила здесь? –

ответ

9

используется частичная специализация:

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.

1

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

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

достаточно.

3

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

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