为什么编译器在以下示例中没有选择我的函数模板重载?
给定以下函数模板:
#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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以执行以下操作:
或使用 SFINAE 删除第一个作为选择候选的函数:
You can either do this:
Or use SFINAE to remove the first function as a selection candidate:
它可以转换为这样的类型,但它是 Derived*。第一个模板函数不需要转换,第二个模板函数需要转换,因此它选择第一个。
这选择了第二个:
顺便说一下,
main
返回一个int
。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:
On a side note,
main
returns anint
.除了关于 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...