0

ここで、このコードの一部を見つけました(少し変更しました):

template<typename F>     
void Eval( const F& f ) {
     f(3.14);
}

私が理解している限り、 Eval 関数は別の関数を引数として取り、その引数の特定の値 (上記の場合は 3.14) に対してその値を返します。しかし、関数の型として何を使用すべきかわかりませんか? その戻り型?では、次の方法で呼び出す必要がありますか?:

Eval<float>(sin)

さらに、なぜポインター (& 記号) を使用するのでしょうか。引数を変更したいので、引数を参照渡ししますか? 関数内でEval関数を再定義しますか? はいの場合、なぜそれをしないのですか? そうでない場合、なぜ & 記号が必要なのですか?

4

6 に答える 6

2

しかし、関数の型として何を使用すべきかわかりませんか?

関数型は のようになりfloat(float)ます。

それとも戻り値の型ですか?最新の C++ では、戻り値の型を推測できます。

template <typename F>
auto Eval(const F & f) -> decltype(f(3.14)) {
    return f(3.14);
}

古いバージョンの言語に固執している場合は、かなりトリッキーです。単純な関数、およびresult_type定義を含む関数型 ( から派生したものなどstd::unary_function)にオーバーロードを提供できます。

template <typename Ret, typename Arg>
Ret eval(Ret (&f)(Arg)) {return f(3.14);}

template <typename F>
typename F::result_type eval(F const & f) {return f(3.14);}

おそらく、特性クラスを定義するか、Boost の関数特性を使用して、これを一般化します

では、次のように呼び出す必要がありますか?

その名前の関数が 1 つしかない場合は、引数依存のルックアップを使用できます。

Eval(sin);

ただし、これがstd::sinの場合、複数のオーバーロードがあるため、型を指定する必要があります。

Eval<float(float)>(sin);

さらに、なぜポインター (& 記号) を使用するのでしょうか。

私たちはしません。これはポインタではなく参照です。

引数を変更したいので、引数を参照渡ししますか?

いいえ。これは への参照constであるため、変更できません。

そうでない場合、なぜ & 記号が必要なのですか?

一部の型はコピーにコストがかかります。他のものはまったくコピーできません。ただし、すべての型は参照によって渡すことができます。したがって、完全に汎用的な関数テンプレートは、すべての型で使用できるようにするために、参照によって引数を取る必要があります。

于 2013-03-14T09:23:29.853 に答える
1

関数のように呼び出すことができるようにオーバーロードされた関数またはクラス/構造体を指す、または関数ポインターであることを意味する、呼び出し可能な型である何かを渡しています。std::function<double(double)>(double)(fooptr*)(double)doubule operator()(double)

f() あなたの中に a があるという事実Evalは、渡された型がでF呼び出すことができるはずであるという手がかりを与えます()

これを使用できる例を次に示します。

#include<iostream>

template<typename F>     
void Eval( const F& f ) {
    std::cout << f(3.14);
}

double foo(double d)
{
   return d + d;
}
int main()
{

 Eval(foo);
}

実際の例

于 2013-03-14T09:19:37.790 に答える
0

私が理解している限り、 Eval 関数は別の関数を引数として取り、その値を返します

いいえ、Evalvoid を返します。どんなf(3.14)リターンも使用されません。

しかし、関数の型として何を使用すべきかわかりませんか? その戻り型?では、次の方法で呼び出す必要がありますか?: Eval<float>(sin)

ほとんどの場合Eval(obj)、 で十分であり、型Fは の型から「推定」されobjます。それがあいまいな場合は、明示する必要があります: Eval<float(float)>(sin)(正しいヘッダー ファイルを含めていただければ幸いです)。引数で「呼び出す」ことができるタイプの「オブジェクト」はすべてdoubleコンパイルされます。

Moreover, why do we use pointers (&-symbol)? 

いいえ、ここconst&は const 参照を意味します。引数に直接アクセスしますが、変更しないことを約束します。

于 2013-03-14T09:36:51.077 に答える
0

C++ では、テンプレートはコンパイル中にインスタンス化されるため、呼び出しをサポートするものを渡せば機能します。

例えば:

class MyClass
{
public:
    void operator() (double d)
    {
        // Do something
    } 
}

MyClass m;

Eval(m);

または:

Eval([](double d) { /* ... */ });

または:

void DoSth(double d)
{
    // ...
}

Eval(DoSth);

const 参照で渡すのはなぜですか? いくつかの理由があります:

  • 渡されたオブジェクトはコピーされないため、パフォーマンスが向上します。
  • 存在しないオブジェクトを渡すことはできません (参照を null にすることはできません)
  • const 参照の const は、オブジェクト自体が関数呼び出し内で変更されないことを保証します
于 2013-03-14T09:20:36.013 に答える
0

値を返したい場合は、次のようなものを使用する必要があります

template<typename F>     
typename F::result_type Eval(F f) {
     return f(3.14);
}

ノート

  1. 関数を値で渡す方が慣用的です。
  2. これは、void戻り型では機能しない場合があります。
  3. 関数は適応可能でなければなりません。
  4. コンパイラが独自に解決できるため、テンプレート パラメーターを渡す必要はありません。
于 2013-03-14T09:22:49.403 に答える