编写专用于类及其子类的函数模板
Writing a function template that is specialised for a class and its subclasses
我正在尝试编写一个函数模板。一个版本应用于不满足另一个版本条件的所有类型;当参数是给定类的基类或该类本身时,应使用另一个版本。
我尝试过对Base&
进行重载,但是当类派生自Base
时,它们使用通用的,而不是特定的。
我也尝试过这种SFINAE方法:
struct Base { };
struct Derived : public Base { };
struct Unrelated { };
template<typename T>
void f(const T& a, bool b = true) {
cout << "not special" << endl;
}
template<typename T>
void f(const Base& t, bool b = is_base_of<Base, T>::value) {
cout << "special" << endl;
}
Base b;
Derived d;
Unrelated u;
f(b); f(d); f(u);
但他们都打印"不特别"。我不擅长SFINAE,我可能只是做错了。如何编写这样的函数?
首先,这些都不会将"特殊"f
称为重载,因为T
无法从函数参数中推断出来。 它的第一个参数需要是 T
类型:
void f(const T& t, bool b = is_base_of<Base, T>::value)
完成此操作后,请注意"特殊"重载实际上不会使用 SFINAE 来影响过载分辨率:is_base_of<T, U>::value
始终有一个值:它要么是true
要么是false
。 若要影响重载解析,需要使用 enable_if
,它基于布尔值有条件地定义类型。
此外,两个重载都需要使用 SFINAE:如果T
派生自基数(或基数类型),则必须启用"特殊"重载,而"非特殊"重载只有在T
不是从基派生时才能启用,否则会出现过载解析歧义。
这两个重载应声明并定义为:
template<typename T>
void f(T const& a, typename enable_if<!is_base_of<Base, T>::value>::type* = 0)
{
cout << "not special" << endl;
}
template<typename T>
void f(T const& t, typename enable_if<is_base_of<Base, T>::value>::type* = 0)
{
cout << "special" << endl;
}
最后,请注意,这里没有专业化。 这两个名为 f
的函数是重载。
这是一个简单的 C++03 方法:
namespace detail // implementation details, users never invoke these directly
{
template<bool B>
struct f_impl
{
template<typename T>
static void f(T const& t) { std::cout << "not specialn"; }
};
template<>
struct f_impl<true>
{
static void f(Base const& t) { std::cout << "specialn"; }
};
}
template<typename T>
void f(T const& t)
{
detail::f_impl<is_base_of<Base, T>::value>::f(t);
}
现场演示。
使用重载执行此操作的一种方法是这样的:
#include <iostream>
using namespace std;
struct Base { };
struct Derived : public Base { };
struct Unrelated { };
void f(...) {
cout << "not special" << endl;
}
void f(const Base& t) {
cout << "special" << endl;
}
int main(){
Base b;
Derived d;
Unrelated u;
f(b);
f(d);
f(u);
return 0;
}
结果:
special
special
not special
采用变量参数列表的重载将采用任何类型的参数,但始终被认为不如任何其他有效的重载合适。
相关文章:
- 由于签名差异,调用了错误的子类函数
- 从子类访问模板类成员时出现"找不到标识符"错误
- 从父类的向量访问子类函数,而无需向下转换
- 在子类函数覆盖中省略具有默认值的参数
- 有没有办法在C++中调用基类的所有子类函数?
- 子类化模板类并连接到信号
- 使用类/函数模板组合进行意外诊断
- C++ 函数无法使用模板为基类的子类派生模板
- 无法调用子类函数,C++
- C++中的类/函数模板占用了我的二进制文件的百分比是多少?
- 子类作为模板模板基类的模板参数,而该类别又是子类函数参数
- 从同一父调用调用不同的子类函数
- C++ 子类的模板子类中的名称解析
- 在子类函数中访问超类友元的受保护数据成员
- 调用子类函数
- 相对于更专业的继承函数,模板更喜欢子类函数
- 接受子类的模板作为对象的模板
- 重载的子类函数,将子类的实例作为参数,如何使用
- 模板化子类和模板化基类的静态成员专用化
- 从模板子类调用模板基类的重写模板成员函数