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));
}
问问题
100 次
2 回答
3
模板参数推导通过推导T
as使您的模板函数完全匹配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 回答