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

发布于 2024-08-08 08:34:18 字数 803 浏览 9 评论 0原文

给定以下函数模板:

#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 而不是重载 #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;
}

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

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

Given the following function templates:

#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)
{
};

Why is it that the following code always invokes overload #1 instead of overload #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;
}

Given that the second parameter of f is a derived type of Base, I was hoping that the compiler would choose overload #2 as it is a better match than the generic type in overload #1.

Are there any techniques that I could use to rewrite these functions so that the user can write code as displayed in the main function (i.e., leveraging compiler-deduction of argument types)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

柠檬 2024-08-15 08:34:18

您可以执行以下操作:

f(v, static_cast<Base*>(&derived));

或使用 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)
{
};

You can either do this:

f(v, static_cast<Base*>(&derived));

Or use SFINAE to remove the first function as a selection candidate:

// 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)
{
};
月下客 2024-08-15 08:34:18

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

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

这选择了第二个:

f(v, static_cast<Base*>(&derived));

顺便说一下,main 返回一个 int

Given that the second parameter of f is a derived type of Base

It's convertible to such, but it is a Derived*. The first template function requires no conversions, and the second requires one, therefore it chooses the first.

This chooses the second:

f(v, static_cast<Base*>(&derived));

On a side note, main returns an int.

韵柒 2024-08-15 08:34:18

除了关于 Koenig Lookup 的明显主题之外,编译器或多或少都很好地实现了这些主题(尤其是较旧的编译器)是相当有问题的),关于模板专业化存在一些陷阱。

专业化要求类型完全匹配(不确定 std 如何定义这一点,但根据我的经验 [gcc,msvc] 派生类将不匹配)。如果您向 Base* 添加丑陋的强制转换,它应该按照您的预期工作,可以选择为 Derived 添加另一个专业化...

Beside the obvious topics about Koenig Lookup that is more or less well implemented by compilers (especially older ones are quite problematic), there are a few pitfalls regarding template specialization.

The specialization requires the types to exactly match (not sure how the std defines this, but from my experience [gcc, msvc] a derived class won't be matched). If you add an ugly cast to Base*, it should work like you intend, optionally add another specialization for Derived...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文