15

この架空のヘッダーファイルを見てください。

template <class T>
class HungryHippo {
public:
    void ingest(const T& object);
private:
    ...
}

さて、文字列への参照HungryHippo<string>が必要になるのは理にかなっていますingest-文字列のコピーは非常にコストがかかる可能性があります!しかし、HungryHippo<int>それはあまり意味がありません。int直接渡すことは非常に安価ですが(ほとんどのコンパイラーはレジスターでそれを行います)、への参照を渡すことintは余分な不必要なレベルの間接参照です。これはすべて戻り値にも当てはまります。

コンパイラに「引数を変更するつもりはないので、何が良いと思うかに応じて、値で渡すか参照で渡すかを決定する」ことを提案する方法はありますか?

関連する可能性のあるいくつかの事柄:

  • を書いtemplate <class T, bool PassByValue> class HungryHippoてからに特化することで、この効果を手動で偽造することができPassByValueます。本当に派手になりたいのなら、とに基づいて推測することもできPassByValueます。いずれにせよ、実装がほとんど同じように見える場合、これは多くの余分な作業であり、コンパイラーは、値を渡すかどうかを決定する上で、私よりもはるかに優れた仕事をすることができると思います。sizeof(T)std::is_trivially_copyable<T>
  • libc ++プロジェクトは、コンパイラーが1レベル上の選択を行えるように多くの関数をインライン化することでこれを解決しているようですが、この場合、の実装ingestはかなり複雑で、インライン化する価値がないとしましょう。コメントで説明されているように、すべてのテンプレート関数はinlineデフォルトです。
4

2 に答える 2

8

ヘッダーはまさにこのboost::call_traits問題を扱っています。こちらをご覧ください。

具体的には、call_traits<T>::param_typeオプションには次の説明が含まれます。

Tが小さな組み込み型またはポインタの場合、はではなく、param_typeとして定義されます。これにより、渡されたパラメーターに依存する場合、関数の本体のループを最適化するコンパイラーの機能を向上させることができます。渡されたパラメーターのセマンティクスは変更されません(部分的な特殊化が必要です)。T constT const&

あなたの場合、ingest次のように定義できます。

template <class T>
class HungryHippo {
public:
    void ingest(call_traits<T>::param_type object);
    // "object" will be passed-by-value for small 
    // built-in types, but passed as a const reference 
    // otherwise
private:
    ...
};

これが実際に実際のコード/コンパイラの組み合わせに大きな違いをもたらすかどうかはわかりません。いつものように、実際のベンチマークを実行して、何が起こるかを確認する必要があります...

于 2012-11-16T00:22:56.897 に答える
0

ブーストのようなトリックcall_traits<T>は、この場合に彼らが主張することを実行しますが、コンパイラが最も重要なケースでこの最適化をまだ行っていないことを想定していると思います。結局のところ、それは些細なことです。const T&aとを受け入れる場合sizeof(T) <= sizeof(void*)、C ++参照セマンティクスによって課せられる不変条件により、コンパイラーは、関数本体全体の値を、それが成功した場合に単純に置き換えることができます。そうでない場合、最悪の場合のオーバーヘッドは、関数プロローグでの引数への1つのポインター逆参照です。

于 2012-11-16T01:53:48.873 に答える