10

次与えられたVC++ 2010の使用:私は上記と呼ばれる "B" を希望なぜ、コンパイラは、オーバーロードされた非テンプレート関数に対してこのテンプレート関数を選択していますか?

class Base { }; 
class Derived : public Base { }; 

template<class T> void foo(T& t); // A 
void foo(Base& base);    // B 

Derived d; 
foo(d);       // calls A 
foo(static_cast<Base&>(d));  // calls B 

を。私はBaseへのキャストでこれを達成することができますが、なぜこれは必要ですか?

Base(組み込み型など)から派生していないすべての型に対してテンプレート関数を呼びたいのですが、クライアントを必要とせずにBaseから派生した型に対して非テンプレートオーバーロードを呼びたい明示的にキャストする。私はまた、過負荷をテンプレートの特殊化にしようとしましたが、その場合も同じ動作が発生します。私が探しているものを得るための慣用的な方法は何ですか?

答えて

12

すべてが同じで、非テンプレート関数が関数テンプレートよりも優先されます。しかし、あなたのシナリオではすべてが等しくない:(A)はT = Derivedと完全に一致するが、(B)は引き数の導出 - ベース変換を必要とする。

あなたはBaseから派生しているタイプでインスタンス化されることから(A)を防止するために(代替失敗はエラーではありません)SFINAEを使用して(このような)特定のケースのためにこれを回避することができます。

#include <type_traits> 
#include <utility> 

template <typename T> 
typename std::enable_if< 
    !std::is_base_of<Base, T>::value 
>::type foo(T& x) 
{ 
} 

void foo(Base& x) 
{ 
} 
+0

これはC++ 11のものですか、それとも古いコードでも機能しますか?クールだから:) –

+1

@ w00te: 'is_base_of'と' enable_if'は、Boost、C++ TR1、およびC++ 11に含まれています。 C++ 11の機能は必要ありません。 C++ 03の言語機能のみを使用してこれらを定義できます。 –

+0

@ w00te:あなたはC++ 03でそれをすることができますが、boostからenable_ifとis_base_ofを取得する必要があります(または独自のロールでC++についていくつか教えてください)。 –

2

オーバーロードされたバージョンよりもタイプがDerivedの引数で呼び出されたときに、テンプレートのバージョンが選択されています。 SFINAEを使用してテンプレートのバージョンを過負荷解決から削除し、BaseまたはDerivedの引数を使用して呼び出すときに、別のバージョンが選択されるようにすることができます。

#include <type_traits> 
#include <iostream> 

class Base { }; 
class Derived : public Base { }; 

template<class T> 
typename std::enable_if< 
    std::is_base_of<Base, T>::value == false 
>::type 
foo(T&) 
{ 
    std::cout << "template foo" << std::endl; 
} 


void foo(Base&) 
{ 
    std::cout << "non-template foo" << std::endl; 
} 


int main() 
{ 
    Derived d; 
    Base b; 

    foo(d); 
    foo(b); 
} 
+0

'is_same'これはここでは不要です。 – Pubby

+0

@Pubbyありがとう、私はそれを修正します – Praetorian

関連する問題