1

私はいくつかの同様の質問を調べましたが、それでも混乱しています。明示的に(コンパイラの最適化などではなく)、C ++ 03互換で、オブジェクトを特殊なテンプレート関数に渡すときにオブジェクトのコピーを回避する方法を理解しようとしています。これが私のテストコードです:

#include <iostream>

using namespace std;

struct C
{
  C() { cout << "C()" << endl;  }
  C(const C&) { cout << "C(C)" << endl; }
  ~C() { cout << "~C()" << endl;  }
};

template<class T> void f(T) { cout << "f<T>" << endl; }

// This shows two possible ways, I don't need two overloads
// If I do it like (2) the function is not called, only if I do it like (1)

template<> void f(C c) { cout << "f<C>" << endl; } // (1)

template<> void f(const C& c) { cout << "f<C&>" << endl; } // (2)

int main()
{
    C c;
    f(c);
    return 0;
}

(1)タイプのオブジェクトを受け入れ、Cコピーを作成します。出力は次のとおりです。

C()
C(C)
f<C>
~C()
~C()

だから私はこれconst C&を避けるためにパラメータ(2)で特殊化しようとしましたが、これは単に機能しません(どうやら理由はこの質問で説明されています)。

ええと、私は「ポインタを渡す」ことができましたが、それはちょっと醜いです。それで、それをどういうわけかうまく行うことを可能にするいくつかのトリックがありますか?

編集:ああ、おそらく私は明確ではありませんでした。私はすでにテンプレート化された関数を持っています

template<class T> void f(T) {...}

しかし今、私はこの関数を特殊化して、別のオブジェクトへのconst&を受け入れたいと思います。

template<> void f(const SpecificObject&) {...}

しかし、私がそれを次のように定義した場合にのみ呼び出されます

template<> void f(SpecificObject) {...}

基本的に、このスペシャライゼーションでやりたいのは、SpecificObjectのようなテンプレートインターフェイスに適応させることです。

template<> void f(SpecificObject obj){ f(obj.Adapted()); } // call the templated version

EDIT2:わかりました、スペシャライゼーションをconst C&このように呼び出すように強制できます:

f<const C&>(c);

しかし、それをこのように機能させる方法はありf(c)ますか?

編集3:誰かが最終的に同様の質問をする場合、私は最終的に別の質問でこのリンクを見つけました、そしてそれは役に立ちます:http ://www.gotw.ca/publications/mill17.htm

4

6 に答える 6

3

テンプレート、オーバーロード、引数の受け渡しという3つの問題を混同しています。

特殊化を削除し、引数をとして渡しますT const&

乾杯&hth。、

于 2011-02-02T15:12:33.970 に答える
2

オーバーロードしてみませんか:

void f(const C& c) { cout << "f(const C&)" << endl; }
于 2011-02-02T15:10:39.447 に答える
2

これはうまくいくでしょう:

int main()
{
    C c;
    f<const C&>(c);
    return 0;
}

あなたの選択肢:

template<typename T> void f(const boost::reference_wrapper<T const>& c) 
    { cout << "f<boost_const_ref&>" << endl; } 

int main()
{
    C c;
    f(boost::cref(c));
    return 0;
}

実際には、boost :: reference_wrapperを使用して、参照を使用する場所に渡します。get()を使用してこれを行うことができますが、boost :: reference_wrapperには参照への暗黙の変換が含まれているため、テンプレートを部分的に特殊化せずboost::cref(c)に、通常のテンプレートに渡すだけでうまくいく可能性があります。

于 2011-02-02T16:14:19.687 に答える
1

したがって、const参照(基本タイプ[int、long、floatなど]に適しています)を常に受け​​入れたくない場合は、少しブーストマジックを使用できます。

#include <iostream>
#include <boost/call_traits.hpp>

using namespace std;

struct C
{
  C() { cout << "C()" << endl;  }
  C(const C&) { cout << "C(C)" << endl; }
  //C& operator=(C const&) { cout << "C=C" << endl; return *this; }
  ~C() { cout << "~C()" << endl;  }
};

template<class T> void foo(typename boost::call_traits<T>::param_type inst) { cout << "f<T>" << endl; }
// specialization for calling class C
template<> void foo<C>(boost::call_traits<C>::param_type inst) { cout << "f<C>" << endl; }

int main()
{
  int i = 0;
  foo<int>(i);
  C c;
  foo<C>(c);
  return 0;
}
于 2011-02-02T15:32:09.737 に答える
1

問題は、実際のパラメーターcがconstではないことです。したがって、メインテンプレートは、型に「const」を追加する必要がないため、より適切に一致します。値と非定数参照を渡す関数を試してみると、コンパイラーはその違いを解決できないことを通知します。

于 2011-02-02T22:12:57.320 に答える
0
#include <iostream>

using namespace std;

struct C
{
  C() { cout << "C()" << endl;  }
  C(const C&) { cout << "C(C)" << endl; }
  ~C() { cout << "~C()" << endl;  }
};

template<class T> void f(const T&) { cout << "f<T>" << endl; }

int main()
{
    C c;
    f(c);
    return 0;
}

これはあなたが望むことをしますが、関数に渡されるすべての値に対してconstrefを使用する必要があります。これがあなたが探していたものであったかどうかはわかりません。

于 2011-02-02T15:20:45.073 に答える