从基础非模板类调用派生模板类方法

时间:2016-04-24 15:38:13

标签: c++ templates inheritance template-specialization

我正在尝试创建以下流程:

拥有一个'基础'类,没有参数或功能,所以我可以坚持 方法中的基本指针。

它的派生类是一个模板,它在给定的模板参数对象类型上实现operator()。

我正在尝试通过使用指向基类的指针,在运行时调用派生类operator()。

我尝试过使用CRTP实现它 (https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) 但是,当派生类是类模板时,这似乎并不适用于其他方式。

这是我的代码:

class Base {};

template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base {
    private:
        typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
        Func_p m_func;
        const Ref_Obj& m_db;

    public:
        Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}

        inline bool operator()(const Obj_Type& obj) const {
            return (m_db.*m_func)(obj);
        }
}

现在,用法在另一个类模板中,它包含Base类指针的向量,如下所示,并且有自己的operator():

template<typename Obj_Type2> /* Upon usage, Obj_Type2 is the same as Obj_Type, this is just to differ the two in the code here */
class BlaBla {
    private:
        std::vector<const Base *> m_vec;

    public:
        /* relevant constructors ... */

        inline bool operator()(const Obj_Type2 &obj) const {
            for(std::vector<const Base *>::const_iterator it = m_vec.begin(); it != m_vec.end(); ++it) {

                /*** This is the problematic line V ***/
                if( (*it).operator()(obj) ) { /* DO SOMETHING */ }                    
        }
}

当然编译器抱怨在下面的代码中标记的有问题的行中没有匹配的函数要求,但是我无法想出办法进行相关的调用。

我想到的第一个解决方案是使用特定对象类型创建虚拟运算符()(...),例如基类中的虚拟运算符()(const uint32_t&amp; obj),它有效,但我的意图是operator()(...)将接收各种对象类型,并为每个类型声明一个虚方法它们并不优雅,似乎打破了我想在这里实现的所有模板概念。

想到的

第二个解决方案,以某种方式将 Ref_Obj Obj_Type 类型名传递给Base类,用于接口方法的排序,这将使用static_cast来调用相应的Derived运算符(如在CRTP中) - 但这似乎不起作用,因为Derived类是一个类模板,而且BlaBla类也不直接知道 Ref_Obj 类型名称。

是否有任何其他方法可以对Deriver operator()进行适当的调用

1 个答案:

答案 0 :(得分:1)

没有明确干净的方法来做到这一点。根本问题在于没有虚拟模板方法。

我能想到实现完全类型擦除的最简洁方法是使用动态转换和虚拟方法:

class Base {
public:

    virtual bool operator()(const Base &) const=0;
};

template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base {
    private:
        typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
        Func_p m_func;
        const Ref_Obj& m_db;

    public:
        Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}

        inline bool operator()(const Base& obj) const override {
            const Obj_Type *derived_obj=dynamic_cast<const Obj_Type *>(&obj);

            if (!derived_obj)
            {
                  throw; // Or maybe return false, or something...
            }
            return (m_db.*m_func)(*derived_obj);
        }
};

Obj_Type也必须来自Base。这可以在运行时完成工作,但是没有编译时类型检查。

另一种方法是咬紧牙关,放弃100%类型擦除:

template<typename Obj_Type>
class Base {
public:

    virtual bool operator()(const Obj_Type &) const=0;
};

template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base<Obj_Type> {
    private:
        typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
        Func_p m_func;
        const Ref_Obj& m_db;

    public:
        Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}

        inline bool operator()(const Obj_Type& obj) const override {
            return (m_db.*m_func)(obj);
        }
};

因此,您仍然可以将某个对象的operator()抽象到其纯接口,并在子类中定义细节。

或者,另一种选择是两者的结合:

class SuperBase {
public:

    virtual bool operator()(const Base &) const=0;
};

template<typename Obj_Type>
class Base : public SuperBase {
public:

    virtual bool operator()(const Obj_Type &) const=0;

    bool operator()(const Base &obj) const override
    {
          // Do the dynamic cast check, and forward it to the other
          // operator().
    }
};