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

模板参数推导通过推导Tas使您的模板函数完全匹配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 可以是完全匹配,首先不需要隐式转换,因此它比非模板函数的基类版本更可取。

如果您发现这有问题,您可以将模板函数专门用于不符合隐式约定的类型,并让它调用非模板化函数。同样,您可以提供与您将使用的确切派生类匹配的非模板版本,这样就不需要隐式转换。这两个选项都比不使用该运算符更痛苦。对您的模板进行编码,以便它们的隐式模板合同要求尽可能少:)

于 2012-08-13T16:35:23.230 回答