2015-01-30 18 views
6

Câu hỏi này rất giống với: "Extract just the argument type list from decltype(someFunction)". Tôi không chắc chắn câu trả lời có làm việc cho những gì tôi đang có ý định mặc dù. Tôi muốn để có thể tạo ra một chức năng mẫu mà suy ra loại đối số thời gian chạy của nó dựa trên loại của một đối số mẫu con trỏ hàm (còi).Có C++ 11, 14 hoặc 17 cung cấp một cách để có được chỉ là các đối số ra khỏi một decltype()?

Để biết ví dụ về trường hợp sử dụng, giả sử tôi muốn sử dụng công cụ D/POS POS thẳng C bằng cách sử dụng thư viện shim được tải bằng LD_PRELOAD. Tôi có thể viết các trình bao bọc riêng biệt cho fopen, fread, fwrite, fclose ... Nếu tất cả các trình bao bọc đó thực hiện các công cụ tương tự, nó sẽ không đẹp nếu tôi có thể định nghĩa một khuôn mẫu có thể nắm bắt được hành vi chung?

dụ phần KHÔNG sử dụng các mẫu đó chứng tỏ nhiều soạn sẵn có liên quan như thế nào:

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

} 

Chúng ta có thể tiết kiệm một số mã sử dụng một mẫu chức năng 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); 
} 

Phải có một cách nào đó chúng ta có thể tránh được chuyển tất cả các kiểu dư thừa đó trong danh sách các tham số mẫu. Những gì tôi muốn làm điều đó tôi đã không tìm thấy cú pháp hợp lệ để được nêu ra (giả định sự tồn tại của một cái gì đó tôi sẽ gọi std :: arguments_of đó là loại giống như trái ngược với 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ó cách nào hợp lệ để làm điều này trong C++ 11, 14 hoặc 17? Làm thế nào, hoặc nếu không, tại sao không?

+0

Có một số vấn đề khác với thiết kế của bạn. Một chuỗi ký tự không thể được sử dụng như một đối số mẫu, cũng như một biểu thức không liên tục như 'real_fclose'. Và bạn không thể gán cho tham số mẫu. –

+0

Tôi có thể thấy nơi nào sẽ thành ngữ hơn để có real_func_ptr làm tham số để wrap_func hàm thay vì mẫu. Nó dường như làm việc theo cách tôi đã có nó với Intel C++ 15 và -std = C++ 11 mặc dù. ICPC 15 có cho phép tôi thực hiện các quy tắc ở đây không? –

Trả lời

9

Bạn sử dụng đặc tả từng phần:

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

Các nếp nhăn là vì bạn không thể một phần chuyên chức năng bạn cần phải sử dụng một lớp mẫu - đây Wrapper.

1

Trong giải pháp mẫu của bạn, Args có thể suy ra, vì vậy

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

là đủ.

3

Bạn có thể sử dụng con trỏ hàm để suy ra các loại trở lại và lập luận:

#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"); 
} 
Các vấn đề liên quan