为什么模板函数不能将指向一个派生类的指针解析为一个基类的指针 [英] Why can't a template function resolve a pointer to a derived class to be a pointer to a base class

查看:166
本文介绍了为什么模板函数不能将指向一个派生类的指针解析为一个基类的指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编译器无法在编译期获取指向一个派生类的指针,并知道它有一个基类?似乎它不能,基于以下测试。



如何让此工作正常?

  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 * to Base * 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 and Derived 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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆