重载泛型类型的函数与给定类型及其子级的函数
Overloading a function for a generic type vs for a given type and its children
我正在尝试编写一对重载函数,一个必须为指向非 B 或 B 的子类型的指针调用,另一个必须调用指向 B 和 B 的子级的指针。起初,我尝试将模板的专用化用于 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 的错误,无论它们是否是 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 << "Tn"; } */
// (1b)
template<typename T>
int f(typename enable_if<!is_base_of<B, T>::value, T>::type *t)
{ cout << "Tn"; }
// (2)
template<typename T>
int f(typename enable_if<is_base_of<B, T>::value, T>::type *t)
{ cout << "Bn"; }
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 << "Tn"; }
// 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 << "Bn"; }
然后运行它
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
现场示例
我还使函数无效函数,因为您没有任何返回语句。
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:返回类型
// (1b)
template<typename T>
enable_if_t<!is_base_of<B, T>::value>
f(T* t)
{ cout << "Tn"; }
// (2)
template<typename T>
enable_if_t<is_base_of<B, T>::value>
f(T* t)
{ cout << "Bn"; }
演示
或作为模板参数:
// (1b)
template<typename T, enable_if_t<!is_base_of<B, T>::value>* = nullptr>
void f(T* t)
{ cout << "Tn"; }
// (2)
template<typename T, enable_if_t<is_base_of<B, T>::value>* = nullptr>
void f(T* t)
{ cout << "Bn"; }
演示
一个非常简单的解决方法是再次传递指针作为第二个函数参数,用于区分两个版本
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);
}
相关文章:
- 为什么在我的函数类型后使用引用运算符 (&) 允许我修改它返回的值?
- 来自 DLL 的函数调用 [表观调用的括号前面的表达式必须具有(指向-)函数类型]
- 是否有任何建议来统一函数类型限定符并简化可恶的函数类型?
- 关于 C++ 中的函数类型定义
- 用于检测函数类型是否为否的特征
- 函数类型参数的模板参数推导
- 标准对此指向成员函数类型模板参数有何说明?是我的代码有误,还是 MSVS 16.6 有问题?
- C++无效的函数类型转换
- STL 函数和函数类型与函数指针类型
- 如何将result_of与函数类型定义一起使用
- 将模板(没有规范)传递给 std::thread() 会出现错误:<未解析的重载函数类型>匹配错误
- C++ 编译错误:gnu_printf是无法识别的格式函数类型
- 专门用于"direct"函数类型(与函数指针类型相对)
- 将函数类型作为模板参数传递不会编译
- 通过参数传递 lambda(无函数类型模板)
- 如何在模板参数中分离函数类型返回类型和参数
- 为什么比较函数类型需要指定为模板参数?
- 带有限定符的函数类型定义用例
- 如何声明对函数类型的常量引用
- 非类型模板参数允许各种函数类型?