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

Calling derived template class method from base non-template class

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

有一个 'Base' class,没有参数或功能,只是为了让我可以持有 方法中的基指针。

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

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

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

这是我的代码:

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

现在,在另一个 class 模板中使用,它包含 Base class 指针的向量,如下所示,并且有自己的 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 */ }                    
        }
}

当然编译器抱怨在下面代码中标记的有问题的行中没有匹配的函数可以调用,但我想不出一种方法来进行相关调用。

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

想到的

第二个解决方案不知何故通过了Ref_ObjObj_Type 类型名称到 Base class,用于某种接口方法,它将使用 static_cast 调用适当的 Derived 运算符(如在 CRTP 中)-但这似乎不是因为 Derived class 是一个 class 模板,而且 BlaBla class 不直接知道 Ref_Obj 类型名。

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

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

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

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().
    }
};