为什么模板函数不能将指向一个派生类的指针解析为一个基类的指针 [英] Why can't a template function resolve a pointer to a derived class to be a pointer to a base class
问题描述
编译器无法在编译期获取指向一个派生类的指针,并知道它有一个基类?似乎它不能,基于以下测试。
如何让此工作正常?
std :: string nonSpecStr =non specialized func;
std :: string const specStr =specialized func;
std :: string const nonTemplateStr =non template func;
class Base {};
class Derived:public Base {};
class OtherClass {};
template< typename T> std :: string func(T * i_obj)
{return nonSpecStr; }
template<> std :: string func< Base>(Base * i_obj)
{return specStr; }
std :: string func(Base * i_obj)
{return nonTemplateStr; }
class TemplateFunctionResolutionTest
{
public:
void run()
{
//函数解析顺序
//非模板函数
// 2.专门的模板函数
// 3.模板函数
Base * base = new Base;
assert(nonTemplateStr == func(base));
Base * derived = new Derived;
assert(nonTemplateStr == func(derived));
OtherClass * otherClass = new OtherClass;
assert(nonSpecStr == func(otherClass));
//为什么不解析为非模板函数?
Derived * derivedD = new Derived;
assert(nonSpecStr == func(derivedD));
}
};
解决方案
Derived * derivedD = new Derived;
assert(nonSpecStr == func(derivedD));
这不会解决到非模板函数,因为你期望它,因为必须执行
Derived *
到Base *
但是这个转换对于模板版本不是必需的,这导致后者在重载解析期间是更好的匹配。
要强制模板函数不匹配
Base
和Derived
可以使用SFINAE拒绝这两种类型。#include< string>
#include< iostream>
#include< type_traits>
#include< memory>
class Base {};
class Derived:public Base {};
class OtherClass {};
template< typename T>
typename std :: enable_if<
!std :: is_base_of< Base,T> :: value,std :: string
> :: type
func(T *)
{returntemplate function ; }
std :: string func(Base *)
{returnnon template function; }
int main()
{
std :: unique_ptr< Base> p1(new Base);
std :: cout<< func(p1.get())< std :: endl;
std :: unique_ptr< Derived> p2(new Derived);
std :: cout<< func(p2.get())<< std :: endl;
std :: unique_ptr< Base> p3(new Derived);
std :: cout<< func(p3.get())< std :: endl;
std :: unique_ptr< OtherClass> p4(new OtherClass);
std :: cout<< func(p4.get())< std :: endl;
}
输出:
非模板函数
非模板函数
非模板函数
模板函数
Is the compiler unable, at compile-time, to take a pointer to a derived class and know that it has a base class? It seems like it can't, based on the following test. See my comment at the end for where the issue occurs.
How can I get this to work?
std::string nonSpecStr = "non specialized func"; std::string const specStr = "specialized func"; std::string const nonTemplateStr = "non template func"; class Base {}; class Derived : public Base {}; class OtherClass {}; template <typename T> std::string func(T * i_obj) { return nonSpecStr; } template <> std::string func<Base>(Base * i_obj) { return specStr; } std::string func(Base * i_obj) { return nonTemplateStr; } class TemplateFunctionResolutionTest { public: 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)); OtherClass * otherClass = new OtherClass; assert(nonSpecStr == func(otherClass)); // Why doesn't this resolve to the non-template function? Derived * derivedD = new Derived; assert(nonSpecStr == func(derivedD)); } };
解决方案Derived * derivedD = new Derived; assert(nonSpecStr == func(derivedD));
This doesn't resolve to the non-template function as you expect it to because to do that a cast from
Derived *
toBase *
must be performed; but this cast is not needed for the template version, which results in the latter being a better match during overload resolution.To force the template function to not match both
Base
andDerived
you can use SFINAE to reject both those types.#include <string> #include <iostream> #include <type_traits> #include <memory> class Base {}; class Derived : public Base {}; class OtherClass {}; template <typename T> typename std::enable_if< !std::is_base_of<Base,T>::value,std::string >::type func(T *) { return "template function"; } std::string func(Base *) { return "non template function"; } int main() { std::unique_ptr<Base> p1( new Base ); std::cout << func(p1.get()) << std::endl; std::unique_ptr<Derived> p2( new Derived ); std::cout << func(p2.get()) << std::endl; std::unique_ptr<Base> p3( new Derived ); std::cout << func(p3.get()) << std::endl; std::unique_ptr<OtherClass> p4( new OtherClass ); std::cout << func(p4.get()) << std::endl; }
Output:
non template function non template function non template function template function
这篇关于为什么模板函数不能将指向一个派生类的指针解析为一个基类的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!