3

型を使用してテンプレートを作成し、その型を含むテンプレート引数を持つ関数を渡したいと思います。

これが私が現在持っているものです:

#include <iostream>

void fooRef(int& ref) { std::cout << "In ref" << std::endl; }
void fooPtr(int* ptr) { std::cout << "In ptr" << std::endl; }

template<typename T, typename F>
void Print(T arg, F func) {
    //DoABunchOfStuff();
    func(arg);
    //DoSomeMoreStuff();
}

int main() {
    int x = 5;
    int& ref = x;

    Print<int*, void(*)(int*)>(&x, &fooPtr);
    Print<int&, void(*)(int&)>(ref, &fooRef);
}

これは機能しますが、関数の呼び出し元に余分な冗長性があるように感じます。理想的には、次のような呼び出しが必要です。

Print<int*, fooPtr>(ptr);
Print<int&, fooRef>(ref); 

Print 関数の呼び出しを簡素化する方法はありますか?

4

3 に答える 3

3

Print 関数の呼び出しを簡素化する方法はありますか?

はい。あなたがしていることは、テンプレートの種類をまったく指定していません。関数テンプレートは、プロセス呼び出しテンプレートの引数推定を通過します。このプロセスでは、関数に渡されるパラメーターの型が推定され、コンパイラーはそれをテンプレート パラメーターと一致させようとします。それが機能する場合、関数はスタンプアウトされ、コンパイラは続行します。したがって、使用した場合のコード

int main() {
    int x = 5;
    int& ref = x;

    Print(&x, &fooPtr);
    Print(std::ref(ref), &fooRef);
}

次に、取得します

In ptr
In ref

Live Example

私が使用した2番目の呼び出しstd::refでは、実際にはref参照によって渡されます。それ以外の場合は、参照するもののコピーを作成しますref

于 2016-09-26T17:18:29.250 に答える
1

可変個引数テンプレートと混合したテンプレート引数推論を使用することで、これを簡素化できます。これを行う方法は次のとおりです。

template<typename FunctionType, typename... ArgumentTypes>
void Print(FunctionType function, ArgumentTypes... args) {
    function(args...);
}

ただし、参照を正しくサポートしたい場合は、参照の転送に頼る必要があります。これにより、コンパイラは、送信された引数の型だけでなく、値の型も推測できます。

template<typename F, typename... Args>
void Print(F function, Args&&... args) {
    function(std::forward<Args>(args)...);
}

これですべて問題ないように見えますが、引数を受け入れる関数を処理する必要があります。呼び出しを有効にする引数のみを受け入れるように関数を制限するには、末尾の戻り値の型を使用します。

// instead of specifying the return type before the function name,
// let's place it at the end and use `decltype` to deduce the right type:
template<typename F, typename... Args>
auto Print(F function, Args&&... args) -> decltype(function(std::declval<Args>()...)) {
    return function(std::forward<Args>(args)...);
}

このコードを使用すると、コンパイラからのエラーがより明確になります。

void func1(int) {}

Print(func1, 1); // works!
Print(func1, 1, 7); // error: no such function to call

それでも戻り値の型として必要voidであり、関数を制限している場合は、そのために頼ることができますvoid_t:

// void_t definition
template<typename...>
using void_t = void;

template<typename F, typename... Args>
auto Print(F function, Args&&... args) -> void_t<decltype(function(std::declval<Args>()...))> {
    function(std::forward<Args>(args)...);
}
于 2016-09-26T17:30:50.127 に答える