C++ 在下面的示例中,为什么编译器没有选择my function template重载?

C++ 在下面的示例中,为什么编译器没有选择my function template重载?,c++,templates,overloading,function-templates,overload-resolution,C++,Templates,Overloading,Function Templates,Overload Resolution,给定以下函数模板: #include <vector> #include <utility> struct Base { }; struct Derived : Base { }; // #1 template <typename T1, typename T2> void f(const T1& a, const T2& b) { }; // #2 template <typename T1, typename T2> vo

给定以下函数模板:

#include <vector>
#include <utility>

struct Base { };
struct Derived : Base { };

// #1
template <typename T1, typename T2>
void f(const T1& a, const T2& b)
{
};

// #2
template <typename T1, typename T2>
void f(const std::vector<std::pair<T1, T2> >& v, Base* p)
{
};
#包括
#包括
结构基{};
派生结构:基{};
// #1
模板
空f(常数T1和a、常数T2和b)
{
};
// #2
模板
空f(常数标准::向量和v,基*p)
{
};
为什么下面的代码总是调用重载1而不是重载2

intmain()
{
std::向量v;
派生的;
f(100200);//显然称为重载#1
f(v,&派生);//始终调用重载#1
返回0;
}
鉴于
f
的第二个参数是
Base
的派生类型,我希望编译器会选择重载2,因为它比重载1中的泛型类型更匹配

我是否可以使用任何技术重写这些函数,以便用户可以编写
main
函数中显示的代码(即利用编译器对参数类型的推断)

假设f的第二个参数是基的派生类型

它是可转换的,但它是派生的*。第一个模板函数不需要转换,第二个模板函数需要转换,因此它选择第一个模板函数

这选择了第二个:

f(v, static_cast<Base*>(&derived));
f(v,静态_转换(&派生));

另一方面,
main
返回一个
int

除了一些明显的主题,这些主题或多或少都是由编译器实现的(尤其是较旧的编译器是相当有问题的),还有一些缺陷


专门化要求类型完全匹配(不确定std如何定义,但根据我的经验[gcc,msvc]派生类不会匹配)。如果您在Base*中添加了一个丑陋的类型转换,它应该按照您的意愿工作,可以选择为派生的…添加另一个专门化。

您可以执行以下操作:

f(v, static_cast<Base*>(&derived));
f(v,静态_转换(&派生));
或使用SFINAE删除作为候选选择的第一个函数:

// Install boost library and add these headers:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>

// #1 - change it to look like this (note the keyword void changed positions)
template <typename T1, typename T2>
typename boost::disable_if<
   typename boost::is_convertible<T2, Base*>, void>::type
f(const T1& a, const T2& b)
{
};

// #2 - this one can stay the same
template <typename T1, typename T2>
void f(const std::vector<std::pair<T1, T2> >& v, Base* p)
{
};
//安装boost库并添加以下标题:
#包括
#包括
//#1-将其更改为如下所示(注意关键字void changed positions)
模板
typename boost::如果<
typename boost::可转换,void>::type
f(常数T1&a、常数T2&b)
{
};
//#2-这个可以保持不变
模板
空f(常数标准::向量和v,基*p)
{
};

谢谢您的解释。我已经从main中删除了返回值,因为它在示例中不是必需的这样您就可以保留int:)并且它短了一个字符!:不管是否需要,C++语言要求“主”以返回类型“int”声明。虽然它与主要问题无关,但仍然是:1。请输入int main()。2.模板函数定义后面跟着空声明“;”。在C++中这是非法的,助力解救!非常聪明!当我刚刚添加了这个。:)唯一可悲的是它的可读性太差了+1无论如何,解释是好的,提出一个解决方案更好:)我希望在c++0x:)中有一个
enable\u ifa
)现在我们有了模板别名,我想知道这是否会起作用:
模板使用enable\u ifa=typename boost::enable\u if::type这样我们就可以执行
模板启用\u ifa f(T)
肯定会让事情更具可读性:)可读性的打击是不幸的。我认为C++0x概念与litb的要求不符;您可以有两个模板,一个模板的类型参数必须符合某个概念,另一个模板的类型参数必须满足不同的概念。不幸的是,在这一举动震惊了我们中的许多人,他们遵循C++标准委员会作为旁观者,委员会在最后一刻撕掉了提案中的概念。必须这样做是有原因的,这里解释的时间太长了。如果你有兴趣,可以在谷歌上搜索StrousTrup的概念删除。
// Install boost library and add these headers:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>

// #1 - change it to look like this (note the keyword void changed positions)
template <typename T1, typename T2>
typename boost::disable_if<
   typename boost::is_convertible<T2, Base*>, void>::type
f(const T1& a, const T2& b)
{
};

// #2 - this one can stay the same
template <typename T1, typename T2>
void f(const std::vector<std::pair<T1, T2> >& v, Base* p)
{
};