我正在尝试为模板化类和所有派生子级实现成员函数模板专业化。它适用于班级本身,但不适用于孩子。
请看下面的示例演示问题:
#include <vector>
struct MyVector : public std::vector<int> {};
struct S {
template <typename T>
int make(T value) {
return 1;
}
template <typename T>
int make(const std::vector<T>& value) {
return 2;
}
};
int main() {
S s;
// return s.make(std::vector<int>{}); // returns 2, perfekt!
return s.make(MyVector{}); // returns 1 but should return 2
}
实时:https://godbolt.org/z/PgYkKf
我在stackoverflow上搜索了几个小时,但是找不到合适的解决方案。我感谢任何提示!
功能模板专业化
第一笔订单。这不是专业。重要的是要解决这个问题。这太重了。这两个功能模板使make
名称超载。过载解析可以在综合其签名后确定哪个更匹配。在您的情况下,编译器可以推断出的两个签名是
int make(MyVector);
int make(std::vector<int> const&);
[一个是身份转换,而另一个则是将引用绑定到一个基数,就转换而言,该基数比“身份”差。这样就选择了第一个重载。
您之前有几个选择:
首选类型别名,例如using MyVector = std::vector<int>;
。它向前发展,完全匹配第二个重载,并且由于功能模板的部分排序而使其被选择。
添加MyVector
重载,代表:
int make(MyVector const& v) { return make(static_cast<MyVector::vector const&>(v)); }
使用更复杂的技术来控制重载分辨率。标准库具有一些用于基于SFINAE的过程控制的实用程序。这将需要将第一个重载更改为此:
template <typename T>
std::enable_if_t<!std::is_convertible_v<T*, std::vector<int>*>, int>
make(T value) {
return 1;
}
但是此方法过于专家友好,并且不会因许多模板重载而迅速扩展。我首先建议使用前两种方法。
功能模板专业化
第一笔订单。这不是专业。重要的是要解决这个问题。这太重了。这两个功能模板使make
名称超载。过载解析可以在综合其签名后确定哪个更匹配。在您的情况下,编译器可以推断出的两个签名是
int make(MyVector);
int make(std::vector<int> const&);
[一个是身份转换,而另一个则需要将引用绑定到基数,就转换而言,该基数比“身份”差。这样就选择了第一个重载。
您之前有几个选择:
首选类型别名,例如using MyVector = std::vector<int>;
。它向前发展,完全匹配第二个重载,并且由于功能模板的部分排序而使其被选择。
添加MyVector
重载,代表:
int make(MyVector const& v) { return make(static_cast<MyVector::vector const&>(v)); }
使用更复杂的技术来控制重载分辨率。标准库具有一些用于基于SFINAE的过程控制的实用程序。这将需要将第一个重载更改为此:
template <typename T>
std::enable_if_t<!std::is_convertible_v<T*, std::vector<int>*>, int>
make(T value) {
return 1;
}
但是此方法过于专家友好,并且不会因许多模板重载而迅速扩展。我首先建议使用前两种方法。