为泛型类型重载函数与为给定类型及其 children
Overloading a function for a generic type vs for a given type and its children
我正在尝试编写一对重载函数,一个必须为指向非 B 或 B 的 child 类型的指针调用,第二个必须为指针调用到 B 和 B 的 children。起初我尝试对 B 使用模板的专业化,但这对 B 的派生 类 不起作用。所以我查找了 SFINAE 和 enable_if
等但无法正常工作。
泛型函数的签名是
(1) template<typename T> int f(T *t)
对于另一个,我尝试像这样使用 enable_if
和 is_base_of
:
(2) template<typename T> int f(typename enable_if<is_base_of<B, T>::value, T>::type *t)
但总是 (1) 被调用。我试图用 (2) 的否定来替换 (1):
(1b) template<typename T> int f(typename enable_if<!is_base_of<B, T>::value, T>::type *t)
现在我得到所有 T 的错误,无论它们是 (children of) B.
我做错了什么?解决方法是什么?
测试代码如下:
#include <type_traits>
#include <iostream>
using namespace std;
class B {};
class D : public B {};
class C {};
// (1)
/* template<typename T>
int f(T *t)
{ cout << "T\n"; } */
// (1b)
template<typename T>
int f(typename enable_if<!is_base_of<B, T>::value, T>::type *t)
{ cout << "T\n"; }
// (2)
template<typename T>
int f(typename enable_if<is_base_of<B, T>::value, T>::type *t)
{ cout << "B\n"; }
int main()
{
B b;
D d;
C c;
f(&b); // Want B; get T with (1), dont compile with (1b)
f(&d); // Want B; get T with (1), dont compile with (1b)
f(&c); // Want T; get T with (1), dont compile with (1b)
return 0;
}
将 SFINAE 移动到我们可以使用的模板参数中
// if not B or a descendant
template<typename T, typename enable_if<!is_base_of<B, T>::value>::type* = nullptr>
void f(T *t)
{ cout << "T\n"; }
// only if B or a descendant
template<typename T, typename enable_if<is_base_of<B, T>::value>::type* = nullptr>
void f(T *t)
{ cout << "B\n"; }
然后 运行 它反对
int main()
{
B b;
D d;
C c;
f(&b); // Want B; get T with (1), dont compile with (1b)
f(&d); // Want B; get T with (1), dont compile with (1b)
f(&c); // Want T; get T with (1), dont compile with (1b)
return 0;
}
我们得到
B
B
T
我还使函数无效,因为您没有任何 return 语句。
typename enable_if<!is_base_of<B, T>::value, T>::type
是不可推导的,所以你必须显式调用:
f<B>(&b); // Want B;
f<D>(&d); // Want B;
f<C>(&c); // Want T;
为了推导,您可以通过一种经典方式使用 SFINAE:return 类型
// (1b)
template<typename T>
enable_if_t<!is_base_of<B, T>::value>
f(T* t)
{ cout << "T\n"; }
// (2)
template<typename T>
enable_if_t<is_base_of<B, T>::value>
f(T* t)
{ cout << "B\n"; }
或作为模板参数:
// (1b)
template<typename T, enable_if_t<!is_base_of<B, T>::value>* = nullptr>
void f(T* t)
{ cout << "T\n"; }
// (2)
template<typename T, enable_if_t<is_base_of<B, T>::value>* = nullptr>
void f(T* t)
{ cout << "B\n"; }
一个非常简单的解决方法是再次传递指针作为第二个函数参数,用于区分两个版本
template<typename T>
void fImpl(T* t, const void*) {
std::cout << "general";
}
template<typename T>
void fImpl(T *b, const B*) {
std::cout << "specific";
}
template<typename T>
void f(T *t) {
fImpl(t, t);
}
我正在尝试编写一对重载函数,一个必须为指向非 B 或 B 的 child 类型的指针调用,第二个必须为指针调用到 B 和 B 的 children。起初我尝试对 B 使用模板的专业化,但这对 B 的派生 类 不起作用。所以我查找了 SFINAE 和 enable_if
等但无法正常工作。
泛型函数的签名是
(1) template<typename T> int f(T *t)
对于另一个,我尝试像这样使用 enable_if
和 is_base_of
:
(2) template<typename T> int f(typename enable_if<is_base_of<B, T>::value, T>::type *t)
但总是 (1) 被调用。我试图用 (2) 的否定来替换 (1):
(1b) template<typename T> int f(typename enable_if<!is_base_of<B, T>::value, T>::type *t)
现在我得到所有 T 的错误,无论它们是 (children of) B.
我做错了什么?解决方法是什么?
测试代码如下:
#include <type_traits>
#include <iostream>
using namespace std;
class B {};
class D : public B {};
class C {};
// (1)
/* template<typename T>
int f(T *t)
{ cout << "T\n"; } */
// (1b)
template<typename T>
int f(typename enable_if<!is_base_of<B, T>::value, T>::type *t)
{ cout << "T\n"; }
// (2)
template<typename T>
int f(typename enable_if<is_base_of<B, T>::value, T>::type *t)
{ cout << "B\n"; }
int main()
{
B b;
D d;
C c;
f(&b); // Want B; get T with (1), dont compile with (1b)
f(&d); // Want B; get T with (1), dont compile with (1b)
f(&c); // Want T; get T with (1), dont compile with (1b)
return 0;
}
将 SFINAE 移动到我们可以使用的模板参数中
// if not B or a descendant
template<typename T, typename enable_if<!is_base_of<B, T>::value>::type* = nullptr>
void f(T *t)
{ cout << "T\n"; }
// only if B or a descendant
template<typename T, typename enable_if<is_base_of<B, T>::value>::type* = nullptr>
void f(T *t)
{ cout << "B\n"; }
然后 运行 它反对
int main()
{
B b;
D d;
C c;
f(&b); // Want B; get T with (1), dont compile with (1b)
f(&d); // Want B; get T with (1), dont compile with (1b)
f(&c); // Want T; get T with (1), dont compile with (1b)
return 0;
}
我们得到
B
B
T
我还使函数无效,因为您没有任何 return 语句。
typename enable_if<!is_base_of<B, T>::value, T>::type
是不可推导的,所以你必须显式调用:
f<B>(&b); // Want B;
f<D>(&d); // Want B;
f<C>(&c); // Want T;
为了推导,您可以通过一种经典方式使用 SFINAE:return 类型
// (1b)
template<typename T>
enable_if_t<!is_base_of<B, T>::value>
f(T* t)
{ cout << "T\n"; }
// (2)
template<typename T>
enable_if_t<is_base_of<B, T>::value>
f(T* t)
{ cout << "B\n"; }
或作为模板参数:
// (1b)
template<typename T, enable_if_t<!is_base_of<B, T>::value>* = nullptr>
void f(T* t)
{ cout << "T\n"; }
// (2)
template<typename T, enable_if_t<is_base_of<B, T>::value>* = nullptr>
void f(T* t)
{ cout << "B\n"; }
一个非常简单的解决方法是再次传递指针作为第二个函数参数,用于区分两个版本
template<typename T>
void fImpl(T* t, const void*) {
std::cout << "general";
}
template<typename T>
void fImpl(T *b, const B*) {
std::cout << "specific";
}
template<typename T>
void f(T *t) {
fImpl(t, t);
}