通过基类指针检查模板类是否相等

时间:2019-02-09 15:46:07

标签: c++ c++11 templates polymorphism subclass

是否可以通过基类指针检查不同的派生模板类是否是同一模板类的专业化?

这可以通过引入中间的非模板基类来实现。但是,我想知道这种中间类的唯一目的是用于标识时是否可以避免这种模式:

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 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
        }
    }
}

2 个答案:

答案 0 :(得分:0)

可能更好的设计是将所需的虚函数添加到接口A,以便您可以直接在A*上调用它们而无需猜测派生类。后者是一种反模式,因为它违反了多态的目的:一种代码可以在不知道其确切类型的情况下与不同类的对象一起工作的想法。您也可以将不同类型的对象放入不同的容器中,而根本不使用基于虚拟函数的多态性。

答案 1 :(得分:0)

在大多数情况下,模板的不同专长是完全不相关的类型。模板参数推导可以从这种类型推导模板及其参数,但这完全在编译时发生。没有可以保证的运行时信息可以判断一个类是否是给定模板的特化,两个类是否是同一模板的特化,等等。

因此,您需要设置一种自己进行测试的方法,但是中间类方法不是唯一的选择。最直接的方法是将测试它的方法放入基类A中:

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; }
};

此模式还允许不仅仅来自一个模板的子类型类别。如果担心的话,它也不会阻止新类“撒谎”其自身类型,但是最好不要尝试阻止这种情况,而应让任何已实现的派生类对自己的行为负责,这可能意味着它想要“几乎完全像”其他某种类型。