我想为一个方法编写两个重载,一个带有作为特定模板实例的参数,另一个用于“其他所有内容”。当参数是模板专门化的实例时,这种方法有效,但对模板专门化的子类无效。例如:
template <class T> class Ptr { public: T* ptr; };
class C {};
typedef Ptr<C> CPtr;
class CPtrSub : public CPtr {};
template <class T> void foo(const T& a, const T& b) {
std::cout << "plain\n";
}
template <class T> void foo(const Ptr<T>& a, const Ptr<T>& b) {
std::cout << "ptr\n";
}
int main() {
CPtr p1, p2;
CPtrSub p3, p4;
foo(p1, p2);
foo(p3, p4);
}
当我运行这个时,输出是:
ptr
plain
除了模板本身之外,是否可以构建为模板的子类选择的重载?
一些
“V”。
template <typename T, typename = std::enable_if<!std::is_convertible<T, CPtr>::value >::type >
void foo(const T& a, const T& b) {
std::cout << "plain\n";
}
但试图走上“可转换为Ptr”的道路<V>对于某些V“产生编译错误(无法推断V):
template <typename T, typename V, typename = std::enable_if<!std::is_convertible_v<T, Ptr<V> > >::value >
void foo(const T& a, const T& b) {
std::cout << "plain\n";
}
class PtrBase {};
template <class T> class Ptr : public PtrBase { public: T * ptr; };
class C {};
typedef Ptr<C> CPtr;
class CPtrSub : public CPtr {};
template <typename T, typename = std::enable_if<!std::is_convertible<T, PtrBase>::value >::type >
void foo(const T& a, const T& b) {
std::cout << "plain\n";
}
template <class T> void foo(const Ptr<T>& a, const Ptr<T>& b) {
std::cout << "ptr\n";
}
int main() {
C c1, c2;
CPtr p1, p2;
CPtrSub p3, p4;
foo(c1, c2);
foo(p1, p2);
foo(p3, p4);
}
生成输出
plain
ptr
ptr
所以彼得的回答是对的。如果有一个通用的答案不依赖于模板基类,那就更好了。
最后的注释:这些元编程特性中的一些在C++ 11、C++ 17和C++ 20中可用。我将使用率降低到C++ 11的可用性。