通过基 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" 其他类型的行为。