std::string nonSpecStr = "non specialized func";
std::string const nonTemplateStr = "non template func";
class Base {};
class Derived : public Base {};
template <typename T> std::string func(T * i_obj)
{
( * i_obj) += 1;
return nonSpecStr;
}
std::string func(Base * i_obj) { return nonTemplateStr; }
void run()
{
// Function resolution order
// 1. non-template functions
// 2. specialized template functions
// 3. template functions
Base * base = new Base;
assert(nonTemplateStr == func(base));
Base * derived = new Derived;
assert(nonTemplateStr == func(derived));
Derived * derivedD = new Derived;
// When the template function is commented out, this
// resolves to the regular function. But when the template
// function is uncommented, this fails to compile because
// Derived does not support the increment operator. Since
// it doesn't match the template function, why doesn't it
// default to using the regular function?
assert(nonSpecStr == func(derivedD));
}
2 に答える
3
T
テンプレート引数の演繹は、として演繹することにより、テンプレート関数を完全に一致させますDerived
。過負荷解決は、関数のシグネチャのみを確認し、本体はまったく確認しません。関数を宣言し、それをコードで呼び出し、後で定義するのは他にどのように機能しますか?
タイプの操作をチェックするこの動作が実際に必要な場合は、SFINAEを使用して行うことができます。
// C++11
template<class T>
auto f(T* p)
-> decltype((*p)+=1, void())
{
// ...
}
T
がサポートされていない場合、これにより置換が失敗しoperator+=
ます。
于 2012-08-13T16:41:50.950 に答える
2
タイプTは完全に一致する可能性があり、そもそも暗黙的な変換を必要としないため、非テンプレート関数のBaseクラスバージョンよりも望ましいです。
暗黙のコントラクトを満たさないタイプ用にテンプレート関数を特殊化し、これに問題がある場合は、代わりに非テンプレート関数を呼び出すようにすることができます。同様に、暗黙の変換が不要になるように、使用する派生クラスと完全に一致する非テンプレートバージョンを提供できます。ただし、これらのオプションはどちらも、その演算子を使用しないよりも面倒です。テンプレートをコーディングして、暗黙のテンプレートコントラクトが必要とするものをできるだけ少なくします:)
于 2012-08-13T16:35:23.230 に答える