14

この質問は、ファンクターの戻り値の型を推測する方法のフォローアップです。 私はそれをより抽象的な方法で再定式化しています。

テンプレート関数の疑似コードを考える

template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(<decl-expr>)
{
// do something
// ............
return fn(<ret-expr>)
}

where<ret-expr>は を含む任意の式であり、 forの戻り値の型をファンクターの戻り値の型と等しく設定argするために何を使用しますか。<decl-expr>ComputeSomething

ファンクターは、クラス、ラムダ、または関数ポインターの場合があります。

これまでに見つけた部分的な解決策。

(a) ecatmur によって行われた私のリンクされた質問に対する回答。本質的には、 の return ステートメントを繰り返してい<decl-expr>ます。問題: エラーが発生しやすく、ローカル変数が含まれていると機能しません。

(b) 関数ポインタに対してのみ機能します

template <typename Arg, typename Ret>
Ret ComputeSomething(Arg arg, Ret(*fn)(Arg))

Arg(c) ファンクターの引数が型(一般には成り立たない可能性があります) でありArg、デフォルト構成可能である必要があると仮定します。

template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(fn(Arg())

(d)テンプレート内の関数の戻り値の型を推定する方法でstd::declval提案されているように、デフォルトで構築可能な制限を解除することになっている which を使用する。誰かがそれがどのように機能するか説明できますか?

template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(fn(std::declval<Arg>())
4

5 に答える 5

12

result_ofを使用します。下位互換性がありdeclval、コードからすべての醜い苦痛を取り除きます。&&実際に値を転送するだけの場合は、右辺値参照修飾子()を追加することを忘れないでください。

私が重要だと思う他の何か:あなたの関数は引数を別の関数に転送します。このような場合、引数を渡すために常に右辺値参照を使用する必要があります。

RETURNS保守性を向上させるだけの場合:戻り型宣言と実際の戻り式の間の繰り返しを最小限に抑えるためのマクロの試みがいくつかありますが、を含む関数本体を許可するものは見たことがありません。実際のreturnステートメントよりも多く。

仕組みについてdeclval:コンパイラに依存します。評価されたコンテンツで発生することは許可されておらず、その引数は不完全な型である可能性があります。20.2.4を参照

于 2012-08-20T07:23:52.987 に答える
11

std::declval宣言されているだけの (定義されていない) 関数テンプレートです。sizeofしたがって、およびへの引数などの未評価のコンテキストでのみ使用できますdecltype。指定された型の右辺値を返すように宣言されています。これにより、式で関数呼び出しのダミー パラメーターを作成するために使用できますdecltype

例えば

typedef decltype(fn(std::declval<Arg>())) t;

typeの右辺値でt呼び出した結果の型であると宣言します。これはあなたのケース (c) ( ) に似ていますが、何も必要としないため、デフォルトのコンストラクターのない型で機能します。fnArgfn(Arg())Arg

戻り式がタイプ のローカル変数を使用するfoo場合decltype(fn(std::declval<foo>()))foo.

名前付きオブジェクトや左辺値参照などの左辺値が必要な場合は、 を使用できますstd::declval<foo&>()。これにより、左辺値または右辺値のどちらを持っているかによって型が異なる場合を処理できます。

于 2012-08-20T10:36:59.070 に答える
5

これが私自身の解決策です。私が得ることができる最高のものです

template <typename Arg, typename Fn>
typename std::result_of<Fn(Arg)>::type ComputeSomething(Arg arg, Fn fn)
于 2012-08-20T12:01:03.883 に答える
3

(c) を何に対しても機能させるには、2 つのオーバーロードが必要です。1 番目 (c) に示すように、2 番目:

template <typename Arg, typename Ret>
Ret ComputeSomething(Arg arg, std::function<Ret(Arg)> fn)

また、gcc バグ 54​​111が示すように、戻り値の型の推定は非常に信頼できません。

于 2012-08-20T07:29:03.220 に答える
2

関数ポインタだけでなく、(b)の変形は次のようになります。

template<typename Arg, typename Ret>
Ret ComputeSomething (Arg arg, function<auto (Arg) -> Ret> f)
于 2012-08-20T07:24:12.787 に答える