我正在尝试为模板化类和所有派生子级实现成员函数模板专用化。它适用于班级本身,但不适用于儿童。
请看下面演示问题的示例:
#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; }
但是这种方法过于专家友好,并且很快就会无法扩展许多模板重载。我首先推荐前两种方法。