Why is the compiler choosing this template function over an overloaded non-template function?

半城伤御伤魂 提交于 2019-12-01 00:32:13

问题


Using VC++ 2010, given the following:

class Base { };
class Derived : public Base { };

template<class T> void foo(T& t);  // A
void foo(Base& base);              // B

Derived d;
foo(d);                            // calls A
foo(static_cast<Base&>(d));        // calls B

I would like "B" to be called above. I can achieve this with a cast to Base, but why is this necessary?

I want the template function to be called for all types not derived from Base (built-in types, etc.), but I want the non-template overload to be called for types derived from Base, without requiring the client to explicitly cast. I also tried making the overload a specialization of the template, but the same behavior occurs in that case. What is the idiomatic way to get what I'm looking for?


回答1:


All things being equal, nontemplate functions are preferred over function templates. However, in your scenario, all things are not equal: (A) is an exact match with T = Derived, but (B) requires a derived-to-base conversion of the argument.

You can work around this for specific cases (like this one) by using SFINAE (substitution failure is not an error) to prevent (A) from being instantiated with a type that is derived from Base:

#include <type_traits>
#include <utility>

template <typename T>
typename std::enable_if<
    !std::is_base_of<Base, T>::value
>::type foo(T& x)
{
}

void foo(Base& x)
{
}



回答2:


The template version is being selected because it is a better match when called with an argument of type Derived than the overloaded version. You can use SFINAE to drop the template version from overload resolution so that the other version is selected when calling with arguments of type Base or Derived.

#include <type_traits>
#include <iostream>

class Base { };
class Derived : public Base { };

template<class T> 
typename std::enable_if<
  std::is_base_of<Base, T>::value == false
>::type
foo(T&)  
{ 
  std::cout << "template foo" << std::endl; 
}


void foo(Base&)
{ 
  std::cout << "non-template foo" << std::endl; 
}


int main()
{
  Derived d;
  Base b;

  foo( d );
  foo( b );
}


来源:https://stackoverflow.com/questions/8594326/why-is-the-compiler-choosing-this-template-function-over-an-overloaded-non-templ

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!