3

重複の可能性:
テンプレートの値渡しまたは const 参照または…?

関数をパラメーターとして取る関数の次の良い習慣は何ですか:

template<class Function> void test1(Function f);
template<class Function> void test2(Function& f);
template<class Function> void test3(const Function& f);

渡される関数は、ファンクター、std::function、関数ポインター、またはラムダ関数にすることができます。

4

2 に答える 2

6

ユニバーサル参照を使用すれば、それについて考える必要はありません:

template<class Function> void test(Function&& f);
于 2012-11-20T22:32:18.660 に答える
4

引数の型を推測する関数テンプレートに引数が渡される場合、引数をどのように渡すかは興味深い問題です。引数の使用の正確な性質は問題ではないことに注意してください。引数が関数オブジェクト、反復子、値などとして使用されるかどうかは、答えるのにかなり無関係です。次の 4 つのオプションがあります。

  1. template <typename T> void f(T&& a)
  2. template <typename T> void f(T& a)
  3. template <typename T> void f(T const& a)
  4. template <typename T> void f(T a)

関数テンプレートが実際に何をするかについては少し重要です:f()その引数aを別の関数に転送することだけがすべての場合、ユニバーサル参照で渡したいと思います。呼び出された関数は詳細を整理し、不適切なオプションを拒否します。もちろん、一般的には便利ですが、転送機能はやや退屈です。

オブジェクトf()に対して実際に何かを行う場合、通常はすぐに次の 2 つのオプションを破棄できます。

  1. ユニバーサル参照で渡すと、それが参照なのか値なのか分からない型になります。これは、値または参照のように動作するため、型を転送する以外にはほとんど役に立ちません。関数が実際に何をするかを指定するだけでは、問題のあるダンスになります。
  2. 通過T const&もあまり役に立ちません。ライフタイムを制御できず、移動も取得もコピー/移動省略もできないオブジェクトへの参照を取得しました。

オブジェクト自体が変更された場合、非const参照でオブジェクトを渡すと便利です。これは明らかに関数のコントラクトの重要な部分であり、関数のクライアントが実行時にオーバーライドできない、課せられた設計上の選択です。

推奨されるアプローチは、引数を値で受け取ることです。一般に、これにより関数の動作の定義がはるかに簡単になり、実際に型が値または参照のセマンティクスに従うかどうかの選択がユーザーに開かれたままになります! 何かが値渡しされるからといって、対象のオブジェクトも値渡しされるわけではありません。特に関数オブジェクトの場合、標準 C++ ライブラリは、値型参照セマンティクスを提供する汎用アダプターも提供しますstd::ref()

もちろん、インターフェイスの設計は微妙で、オプションの 1 つ 1 つが正当化される場合もあります。ただし、一般的な経験則として、非常に単純だと思います。

  1. 転送関数はユニバーサル参照を使用します。
  2. 引数で何かを行う関数は、値を使用します。

...そしてもちろん、これらの規則は、型が推定される関数テンプレートへの引数にのみ適用されます。

于 2012-11-20T23:00:01.723 に答える