2011-02-02 19 views
1

私はいくつかの同様の質問を見てきましたが、私はまだ混乱しています。私はを明示的に(コンパイラの最適化などではなく)にして、特化テンプレート関数に渡すときにオブジェクトのコピーを避けようとしています。ここに私のテストコードは次のとおりです。テンプレートはconst参照で渡す

#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のオブジェクトを受け取り、そしてコピーを作成します。ここでは、出力は次のようになります(どうやら理由はthis questionに説明されている)

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

は、だから私はこれを回避するために、(2) const C&パラメータに特化しようとしたが、これは単に動作しません。

まあ、私は "ポインタを渡す"ことができましたが、それは一種の醜いです。それで何とかうまくいくことを可能にするトリックはありますか?

編集:ああ、おそらく私は明確ではありませんでした。私はすでにテンプレート関数に

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

を持っている。しかし、今、私は別のオブジェクトへのconst &を受け入れるために、この機能を特化したい:

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

しかし、私は

としてそれを定義した場合にのみ呼び出されます
template<> void f(SpecificObject) {...} 

基本的には、SpecificObject

01のようなテンプレートインターフェイスに適応させることです
template<> void f(SpecificObject obj){ f(obj.Adapted()); } // call the templated version 

EDIT2:[OK]を、私はこのように呼ばれるconst C&専門強制することができます:

f<const C&>(c); 

をしかし、それだけでf(c)として、次のように動作させるための方法がありますか?誰か最終的に同様の質問を持っている希望の場合、私は最終的に別の質問では、このリンクを見つけて、それが便利です::

EDIT3

void f(const C& c) { cout << "f(const C&)" << endl; } 
+0

私はこの2つの特殊化を定義する理由が見つからないため、const参照とコピーを区別する必要があります。そして、私はそれらを区別する方法がないと思う。 –

+0

@ mattia.penati:これは私の意図ではありませんでした。実際には –

+0

です。まず、関数呼び出しで暗黙コピーを避けたい場合は、コピーコンストラクタの前に 'explicit'を置くことができます。これで、関数fを 'テンプレート f(T const&)'と定義できます。それ以外の場合は過負荷を使用します。他に方法はありません。 –

答えて

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; 
} 
+0

私のテンプレート関数は 'f 'なのでconst参照を受け入れる必要はありませんが、私の専門化では 'const SpecificObject&'、すなわち 'f 'のように特殊化する方法を見つけることができません。 –

+0

@ 7vies、それは 'call_traits'の美しさです。自動的に' SpecificObject'のためにconst参照を通らなければならないと推測します。他の型については、生成された 'foo'が呼び出されます(値またはconst参照のいずれかで) – Nim

+0

@Nim:Okですが、なぜ' param_type'が2回あるのですか? 2番目のケースでは 'const_reference'ですか?編集:ああ私は 'param_type'の意味を読んだので、今私は参照してください... –

2

テンプレート、オーバーロード、および引数渡しの3つの問題を融合させたものです。

特殊化を削除し、引数をT const&として渡してください。

乾杯& HTH。、

+0

これは、バイナリバージョンのあいまいなオーバーロードになります。 –

+0

私はそうしても動作しません。 (2)と私がリンクしている質問を参照してください。 –

+0

さて、 'template <>'を省略するとうまくいくようですが、オーバーロードしたくないので、テンプレートに参照渡ししたいと思っています。 –

3

あなたがしている:あなたが過負荷にならないのはなぜhttp://www.gotw.ca/publications/mill17.htm

+0

作業スニペットをお願いしますか? –

+0

@ 7views: 'f'の特殊化を取り除くだけです。 1つの関数テンプレートが残っています。仮引数の型を 'T const&'に変更してください。乾杯&乾杯 –

+0

私の質問は明確ではありませんでした。(私は明確にしようとした。 –

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; 
} 

は、これは、あなたが希望何んが、あなたは、関数に渡されるすべての値についてのconst参照を使用する必要があります。これがあなたが探していたものかどうかはわかりません。

+0

更新を参照してください。 –

+0

ああ、私が最初に考えたのは、 – daramarak

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; 
} 

を、あなたがそれを使用したい場所に介して基準を渡すために、ブースト:: reference_wrapperを使用します。 boost :: reference_wrapperは暗黙の変換をリファレンスに戻しますが、テンプレートの部分的な特殊化を行わずに、boost::cref(c)を通常のものに渡すだけです。

+0

私もこれを答えとして受け入れます... –

1

問題は、実際のパラメータcはconstではないため、メインテンプレートは型に 'const'を追加する必要がないため、よりマッチします。値渡しと非const参照渡しの関数を試してみると、コンパイラはその違いを解決できないことを伝えます。