6

この質問は、「 decltype(someFunction) から引数の型リストだけを抽出する」と非常によく似ています。そこにある答えが、私が意図していることに対して機能するかどうかはわかりません。関数ポインターのテンプレート引数 ( whistle )の型に基づいてランタイム引数の型を推測するテンプレート関数を作成できるようにしたいと考えています。

ユースケースの例として、LD_PRELOAD でロードされた shim ライブラリを使用して、ストレートな C POSIX ファイル I/O を計測したいとします。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::result_of の反対のような std::arguments_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 でこれを行う有効な方法はありますか? どのように、またはそうでない場合、なぜですか?

4

3 に答える 3

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

于 2015-01-30T16:38:50.307 に答える
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");
}
于 2015-01-30T17:42:04.383 に答える