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

2 に答える 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 に答える