为什么编译器在以下示例中没有选择我的函数模板重载?

Ste*_*idi 5 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>
void f(const std::vector<std::pair<T1, T2> >& v, Base* p)
{
};
Run Code Online (Sandbox Code Playgroud)

为什么以下代码总是调用#1而不是#2重载?

int main()
{
    std::vector<std::pair<int, int> > v;
    Derived derived;

    f(100, 200);  // clearly calls overload #1
    f(v, &derived);         // always calls overload #1

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

鉴于第二个参数f是派生类型Base,我希望编译器选择重载#2,因为它比重载#1中的泛型类型更好.

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

Den*_*nis 12

你可以这样做:

f(v, static_cast<Base*>(&derived));
Run Code Online (Sandbox Code Playgroud)

或者使用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)
{
};
Run Code Online (Sandbox Code Playgroud)


GMa*_*ckG 8

鉴于f的第二个参数是Base的派生类型

它可以转换为这样,但它是Derived*.第一个模板函数不需要转换,第二个需要一个,因此它选择第一个.

选择第二个:

f(v, static_cast<Base*>(&derived));
Run Code Online (Sandbox Code Playgroud)

在旁注中,main返回一个int.

  • 是否必要,C++语言_requires_'main'声明为返回类型'int'. (3认同)