2015-01-30 21 views
6

Bu soru çok benzer: "Extract just the argument type list from decltype(someFunction)". Ben de cevaplarımın istediğim gibi çalıştığından emin değilim. Bir işlev imleci şablonu argümanının türüne (ıslık) dayalı olarak çalışma zamanı argümanlarının türünü belirten bir şablon işlevi yaratabilmek istiyorum.C++ 11, 14 veya 17, yalnızca bir decltype()? Argümanlarını almanın bir yolunu sunuyor mu?

Örnek bir kullanım örneği için, diyelim ki LD_PRELOAD ile yüklenen bir shim kitaplığı kullanarak düz C POSIX dosyası G/Ç'yi enstrümanlamak istiyorum. Fopen, felling, fwose, fclose için ayrı paketler yazabilirim ... Eğer tüm bu paketler benzer şeyler yaparsa, ortak davranışı yakalayan bir şablon tanımlayabilirsem hoş olmaz mıydı?

çok Demirbaş katılır nasıl kullanılacağını gösterir şablonları kullanarak DEĞİL

Kısmi örnek:

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

lazım bazı yol var önleyebilirsiniz edilecek oluyor:

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

} 

Biz variadic şablon işlevi kullanarak bazı kod kaydedebilirsiniz Ancak bu gereksiz yazı tiplerinin tümünü şablon parametrelerinin listesinden geçirerek.

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

: Ya ben henüz geçerli sözdizimi bulamadı bunu istiyorum (ben std arayacağım :: o std tersi :: result_of gibi çeşit var arguments_of şeyin varlığını öngörür) Bunu C++ 11, 14 veya 17'de yapmak için geçerli bir yol var mı? Nasıl, ya da olmasın, neden olmasın?

+0

. Bir dize değişmezi şablon argümanı olarak kullanılamaz, ya da "real_fclose" gibi sabit olmayan bir ifade olarak kullanılamaz. Ve bir şablon parametresine atayamazsınız. –

+0

Ben şablon yerine işlev wrap_func bir parametre olarak real_func_ptr sahip daha aptalca nerede olacağını görebiliyordu. Intel C++ 15 ve -std = C++ 11 ile aldığım şekilde çalışıyor gibi görünüyor. ICPC 15 sadece kuralları burada bırakmamı sağlıyor mu? –

cevap

9

Sen kısmi uzmanlaşma kullanı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) { /* ... */ } 
}; 

kırışıklık kısmen fonksiyonlarını uzman olamaz çünkü bir sınıf şablonu kullanmak gerektiğidir - burada Wrapper. şablonunuzu çözümde

1

, Args böylece

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

yeterlidir, sonucuna varılabilir.

3

Sen iade ve argüman tipini anlar işlev işaretçisi kullanabilirsiniz: sizin tasarımıyla diğer bazı sorunlar vardır

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