当我因模板而无法使用纯虚函数时简化类设计

时间:2016-06-04 07:54:35

标签: c++ templates

我有两个类AB,如下所示,它们都实现了一个依赖于模板化方法g的方法f(在两者中重复相同的脚本)。如何避免重复gAB的{​​{1}}方法中的代码?

class A {
public: 
    template<typename T>
    void f() {} 

    void g() {
        f<int>();
        f<double>();
        // etc.
    }
};

class B {
public: 
    template<typename T>
    void f() {} 

    void g() {
        //The same scipt as that of A::g() 
        f<int>();
        f<double>();
        // etc.
    }
};

如果f未被模板化,那么我会将g移动到基类,定义纯虚函数f并简化AB如下:

class Base {
public: 
    virtual Base() = default;
    virtual void f() = 0;   
    void g() { f(); }
};

class A : public Base {
public: 
    void f() {} 
};

class B : public Base {
public: 
    void f() {} 
};

但是,我想知道f被模板化时是否存在类似的方法。

3 个答案:

答案 0 :(得分:2)

CRTP在这里工作正常。
它遵循一个最小的工作示例:

template<typename D>
class X {
public:
    void g() {
        D &d = static_cast<D&>(*this);
        d.template f<int>();
        d.template f<double>();
        // etc.
    }
};

class A: public X<A> {
public: 
    template<typename T>
    void f() { } 
};

class B: public X<B> {
public: 
    template<typename T>
    void f() { }
};

int main() {
    B b{};
    b.g();
}

只要f在派生类中公开,它就是一个很好的解决方案 否则,您必须在这些类中添加这些丑陋的friend class语句:

class A: public X<A> {
private:
    friend class X<A>;

    template<typename T>
    void f() { } 
};

class B: public X<B> {
private:
    friend class X<A>;

    template<typename T>
    void f() { }
};

答案 1 :(得分:1)

使g成为非成员函数模板。

template<typename T>
void g(T& v) {
    v.f<int>();
    v.f<double>();
}

然后你可以传递AB。如果您需要访问私人会员,您可以将其变成朋友。

答案 2 :(得分:0)

正如对@Benjamin Lindley回答的评论所述,我有以下解决方案,我决定在我的真实代码中使用。我相信它很简单,避免重复代码,g_helper的实现可以隐藏在cpp文件中。

template<class T>
void g_helper(T& t) {
    t.template f<int>();    
    t.template f<double>();
    // etc.
}

class A {
public: 
    template<typename T> 
    void f() {} 

    void g() {
        g_helper(*this);
    }
};

class B {
public: 
    template<typename T>
    void f() {} 

    void g() {
        g_helper(*this);
    }
};