如何创建包含成员函数和派生类的模板调用



我在类中封装了一个状态机之类的东西。这可以通过依次调用一系列成员函数来完成操作。我还有几个派生类,我想对它们执行相同的序列。有一种方法,我可以模板这个代码?

#include <iostream>
class MyClass {
    std::string name;
public:
    typedef void (MyClass::*Function)(std::ostream &ostr);
    void Func1(std::ostream &ostr) { ostr << "F1" << name << std::endl; };
    void Func2(std::ostream &ostr) { ostr << "F2" << std::endl; };
    static Function printers[];
    void Print(std::ostream &ostr);
};
MyClass::Function MyClass::printers[] = {
    &MyClass::Func1,
    &MyClass::Func2,
    NULL
};
void MyClass::Print(std::ostream &ostr)
{
    // various stuff to do before
    // ...
    int i = 0;
    for (Function *fp = printers; *fp; fp++, i++) {
        std::cerr << "Calling function " << i << std::endl;
        ((this)->*(*fp))(ostr);
        std::cerr << "Called function " << i << std::endl;
    }
    // other stuff here...
}
class DerClass: public MyClass {
    int index;
public:
    typedef void (DerClass::*Function)(std::ostream &ostr);
    void Func3(std::ostream &ostr) { ostr << "F3" << index << std::endl; };
    static Function printers[];
    void Print(std::ostream &ostr);
};
DerClass::Function DerClass::printers[] = {
    &DerClass::Func1,
    &DerClass::Func3,
    NULL
};
// I'd rather not repeat all this stuff, can I template it??
void DerClass::Print(std::ostream &ostr)
{
    // various stuff to do before
    // ...
    int i = 0;
    for (Function *fp = printers; *fp; fp++, i++) {
        std::cerr << "Calling function " << i << std::endl;
        ((this)->*(*fp))(ostr);
        std::cerr << "Called function " << i << std::endl;
    }
    // other stuff here...
}
int main()
{
    MyClass cl1;
    cl1.Print(std::cout);
    DerClass cl2;
    cl2.Print(std::cout);
}

代码运行,工作,但我想只写一次打印例程,而不是为每个新类,有办法做到这一点,模板?其他类?

我希望是这样的

template <class T>
void T::Print(std::ostream &str) {
    int i = 0;
    for (Function *fp = printers; *fp; fp++, i++) {
    std::cerr << "Calling function " << i << std::endl;
    ((this)->*(*fp))(ostr);
    std::cerr << "Called function " << i << std::endl;
    }
}

这不能编译。

错误:无效使用模板类型参数' T ' voidT::Print(std::ostream &str) {

我宁愿把它写成注释,但是代码量根本就不容易读。

下面你可以找到一个关于如何"继承"你的Print的可能的解决方案。

这只能作为建议或提示。特别是printers的初始化并没有以一种"好的方式"完成。

希望对你有所帮助

#include <iostream>
#include <string>

template <class Derived>
class MyClass {
    std::string name;
protected:
    typedef void (Derived::*Function)(std::ostream &ostr);
    Function* printers;
public:
    MyClass() 
        :printers(nullptr)
    {
    }
    ~MyClass()
    {
        delete[] printers;
    }
    virtual void initPrinters()
    {
        if (printers == nullptr)
        {
            printers = new Function[3];
            printers[0] = &MyClass<Derived>::Func1;
            printers[1] = &MyClass<Derived>::Func2;
            printers[2] = NULL;
        }
    }
    void destroyPrinters()
    {
        if (printers != nullptr)
        {
            delete[] printers;
        }
    }
    void Print(std::ostream &ostr)
    {
        initPrinters();
        // various stuff to do before
        // ...
        int i = 0;
        for (Function *fp = printers; *fp; fp++, i++) {
            std::cerr << "Calling function " << i << std::endl;
            (((Derived*)this)->*(*fp))(ostr);
            std::cerr << "Called function " << i << std::endl;
        }
        // other stuff here...
    }
    void Func1(std::ostream &ostr) { ostr << "F1" << name << std::endl; };
    void Func2(std::ostream &ostr) { ostr << "F2" << std::endl; };
};
template <>
class MyClass<void> : public MyClass<MyClass<void>>
{
};
class DerClass : public MyClass<DerClass> {
    int index;
public:
    virtual void initPrinters() override
    {
        if (printers == nullptr)
        {
            printers = new Function[3];
            printers[0] = &DerClass::Func1;
            printers[1] = &DerClass::Func3;
            printers[2] = NULL;
        }
    }
    void Func3(std::ostream &ostr) { ostr << "F3" << index << std::endl; };
};
int main()
{
    MyClass<void> cl1;
    cl1.Print(std::cout);
    DerClass cl2;
    cl2.Print(std::cout);
}

EDIT: Second Approach

在我看来这个更漂亮。此外,它是更少的代码,它可以由编译器优化:

#include <iostream>
#include <string>

class MyClass {
    std::string name;
protected:

    template <class T>
    void print(std::ostream &ostr, void(T::*printFunc)(std::ostream&))
    {
        (((T*)this)->*printFunc)(ostr);
    }
    template <class T, typename... PrintFunctions>
    void print(std::ostream &ostr, void(T::*printFunc)(std::ostream&), PrintFunctions... printFuncs)
    {
        (((T*)this)->*printFunc)(ostr);
        print(ostr, printFuncs...);
    }
public:
    virtual void Print(std::ostream &ostr)
    {
        print(ostr, &MyClass::Func1, &MyClass::Func2);
    }
    void Func1(std::ostream &ostr) { ostr << "F1" << name << std::endl; };
    void Func2(std::ostream &ostr) { ostr << "F2" << std::endl; };
};
class DerClass : public MyClass {
    int index;
public:
    virtual void Print(std::ostream &ostr) override
    {
        print(ostr, &DerClass::Func1, &DerClass::Func3);
    }
    void Func3(std::ostream &ostr) { ostr << "F3" << index << std::endl; };
};
int main()
{
    MyClass cl1;
    cl1.Print(std::cout);
    DerClass cl2;
    cl2.Print(std::cout);
}

如果"各种东西"one_answers"其他东西"是不同的,你可以使这些部分虚拟。

但是你不能在基类中调用子类的成员函数,所有的函数都需要具有相同的类型。

一个建议可能是间接通过自由函数。

class MyClass;
typedef void (*Printer)(MyClass*, std::ostream&);
class MyClass {
    std::string name;
public:
    MyClass();
    void Func1(std::ostream &ostr) { ostr << "F1" << name << std::endl; };
    void Func2(std::ostream &ostr) { ostr << "F2" << std::endl; };
    void Print(std::ostream &ostr);
protected:
    MyClass(Printer* ps) : myprinters(ps) {}
    virtual void PrePrint() { /* Various stuff... */ }
    virtual void PostPrint() { /* Other stuff... */ }
private:
    Printer* myprinters;
};
void MyFunc1(MyClass* obj, std::ostream& os) { obj->Func1(os); }
void MyFunc2(MyClass* obj, std::ostream& os) { obj->Func2(os); }
Printer myclassprinters[] = {
    &MyFunc1,
    &MyFunc2,
    NULL
};
MyClass::MyClass()
    : myprinters(myclassprinters)
{
}
void MyClass::Print(std::ostream &ostr)
{
    PrePrint();
    int i = 0;
    for (Printer *fp = myprinters; *fp; fp++, i++) {
        std::cerr << "Calling function " << i << std::endl;
        (*fp)(this, ostr);
        std::cerr << "Called function " << i << std::endl;
    }
    PostPrint();
}
class DerClass: public MyClass {
public:
    DerClass();
    void Func3(std::ostream &ostr) { ostr << "F3" << index << std::endl; };
protected:
    void PrePrint() { /* More stuff... */ }
};
// C-cast for conciseness only. Use something safer in the real world.
void DerFunc(MyClass* obj, std::ostream& ostr) { ((DerClass*)obj)->Func3(ostr); }
Printer derclassprinters[] = {
    &MyFunc1,
    &DerFunc,
    NULL
};
DerClass::DerClass()
    : MyClass(derclassprinters)
{
}

为每个实例使用一个指针成员——我假设您不想为每个实例存储整个函数表。

最新更新