通过基 class 指针检查模板 class 是否相等
Check for template class equality through base class pointer
是否可以通过基 class 指针检查不同的派生模板 class 是否是同一模板 class 的特化?
这可以通过引入一个中间的非模板基础-class来实现。但是,我想知道当这个中间体 class 的唯一目的是用于识别时,这种模式是否可以避免:
class A{}
class B_base : public A{}
template<T>
class B : public B_base {}
// There may be other derived classes of A
template<T>
class C: public A{}
void main() {
// ... some vector of pointers to A derived objects
std::vector<A*> v;
for(auto& i : v){
// Check whether i is any specialization of B through a
// dynamic_cast to the intermediate class
if(dynamic_cast<B_base*>()){
// This is a B_base object,
}
}
}
理想情况下,我想要这样的东西,以避免中间 class。
class A{}
template<T>
class B : public A{}
// There may be other derived classes of A
template<T>
class C: public A{}
void main() {
// ... some vector of pointers to A derived objects
std::vector<A*> v;
for(auto& i : v){
// Check whether i is any specialization of B
if(templateTypeId(i) == templateTypeId(B*)){
// This is a B object with some unknown specialization
}
}
}
可能更好的设计是将所需的虚函数添加到接口 A
,这样您就可以直接在 A*
上调用它们而无需猜测派生的 class。后者是一种反模式,因为它违背了多态性的目的:一段代码可以在不知道其确切类型的情况下处理不同 classes 的对象的想法。还不如把不同类型的对象放到不同的容器里,根本不用基于虚函数的多态
在大多数情况下,模板的不同特化是完全不相关的类型。模板参数推导可以从这样的类型中推导出模板及其参数,但这完全发生在编译时。没有保证 运行 时间信息可以判断一个 class 是否是给定模板的特化,两个 class 是否是同一模板的特化等。
因此您需要自己设置一种方法来对此进行测试,但是您的中间 class 方法不是唯一的选择。最直接的方法是将一种测试方法放入基数 A
class:
class A {
public:
virtual ~A() = default;
virtual bool is_B() const noexcept { return false; }
};
template <class T>
class B : public A {
public:
bool is_B() const noexcept override { return true; }
};
虽然如果有几个不同的 B 类类别要测试,这会有点难看,如果可以用新的子类型扩展 A
,然后测试那些,则不起作用子类型以类似的方式。
另一个想法是将类型检查与对象地址相关联:
struct type_tag {
constexpr type_tag() = default;
type_tag(const type_tag&) = delete;
type_tag& operator=(const type_tag&) = delete;
};
class A {
public:
virtual ~A() = default;
virtual bool matches_type(const type_tag&) const
{ return false; }
};
inline constexpr type_tag B_tag{};
template <class T>
class B {
public:
bool matches_type(const type_tag& tag) const override
{ return &tag == &B_tag; }
};
此模式还允许并非仅来自一个模板的子类型类别。它也不会阻止新的 class 来自 "lying" 关于它自己的类型,如果这可能是一个问题,但最好不要试图阻止它,但让任何已实现的派生 class 对自己的行为负责,这可能意味着它想采取 "almost exactly like" 其他类型的行为。
是否可以通过基 class 指针检查不同的派生模板 class 是否是同一模板 class 的特化?
这可以通过引入一个中间的非模板基础-class来实现。但是,我想知道当这个中间体 class 的唯一目的是用于识别时,这种模式是否可以避免:
class A{}
class B_base : public A{}
template<T>
class B : public B_base {}
// There may be other derived classes of A
template<T>
class C: public A{}
void main() {
// ... some vector of pointers to A derived objects
std::vector<A*> v;
for(auto& i : v){
// Check whether i is any specialization of B through a
// dynamic_cast to the intermediate class
if(dynamic_cast<B_base*>()){
// This is a B_base object,
}
}
}
理想情况下,我想要这样的东西,以避免中间 class。
class A{}
template<T>
class B : public A{}
// There may be other derived classes of A
template<T>
class C: public A{}
void main() {
// ... some vector of pointers to A derived objects
std::vector<A*> v;
for(auto& i : v){
// Check whether i is any specialization of B
if(templateTypeId(i) == templateTypeId(B*)){
// This is a B object with some unknown specialization
}
}
}
可能更好的设计是将所需的虚函数添加到接口 A
,这样您就可以直接在 A*
上调用它们而无需猜测派生的 class。后者是一种反模式,因为它违背了多态性的目的:一段代码可以在不知道其确切类型的情况下处理不同 classes 的对象的想法。还不如把不同类型的对象放到不同的容器里,根本不用基于虚函数的多态
在大多数情况下,模板的不同特化是完全不相关的类型。模板参数推导可以从这样的类型中推导出模板及其参数,但这完全发生在编译时。没有保证 运行 时间信息可以判断一个 class 是否是给定模板的特化,两个 class 是否是同一模板的特化等。
因此您需要自己设置一种方法来对此进行测试,但是您的中间 class 方法不是唯一的选择。最直接的方法是将一种测试方法放入基数 A
class:
class A {
public:
virtual ~A() = default;
virtual bool is_B() const noexcept { return false; }
};
template <class T>
class B : public A {
public:
bool is_B() const noexcept override { return true; }
};
虽然如果有几个不同的 B 类类别要测试,这会有点难看,如果可以用新的子类型扩展 A
,然后测试那些,则不起作用子类型以类似的方式。
另一个想法是将类型检查与对象地址相关联:
struct type_tag {
constexpr type_tag() = default;
type_tag(const type_tag&) = delete;
type_tag& operator=(const type_tag&) = delete;
};
class A {
public:
virtual ~A() = default;
virtual bool matches_type(const type_tag&) const
{ return false; }
};
inline constexpr type_tag B_tag{};
template <class T>
class B {
public:
bool matches_type(const type_tag& tag) const override
{ return &tag == &B_tag; }
};
此模式还允许并非仅来自一个模板的子类型类别。它也不会阻止新的 class 来自 "lying" 关于它自己的类型,如果这可能是一个问题,但最好不要试图阻止它,但让任何已实现的派生 class 对自己的行为负责,这可能意味着它想采取 "almost exactly like" 其他类型的行为。