虚拟模板解决方法没有太多冗长

问题描述 投票:0回答:1

我正在寻找一种解决方法,以解决C ++中缺少虚拟模板函数的问题。我理想的是能够将我的派生类存储在一个向量中,迭代它们并调用正确的函数,所以在伪代码中:


template<typename T>
struct Output
{
    ...
};

struct Base
{
    template<typename T>
    virtual void doSomething(Output<T>& out) = 0;
};

struct DerivedA : public Base
{
    DerivedA(const char* filename) {...}
    template<typename T>
    void doSomething(Output<T>& out) final
    {
        ...
    }
};

struct DerivedB : public Base
{
    DerivedB(const char* filename) {...}
    template<typename T>
    void doSomething(Output<T>& out) final
    {
        ...
    }
};

int main()
{
    std::vector<Base*> vec;
    vec.push_back(new DerivedA("data1.bin"));
    vec.push_back(new DerivedB("data2.bin"));
    vec.push_back(new DerivedA("data3.bin"));
    vec.push_back(new DerivedA("data4.bin"));

    Output<float> outF;
    Output<double> outD;
    Output<int> outI;
    for (auto e : vec)
    {
        e->doSomething(outF);
        e->doSomething(outD);
        e->doSomething(outI);
    }

    return 0;
}

如果解决方法尽可能“无痛”且非冗长,我会更喜欢它(因为我使用模板来避免首先为n种不同类型重新定义相同的函数n次)。我想到的是用std :: map制作自己的vtable,并做一些dynamic_casts。我正在寻找任何更好的想法,或者如果你认为这个想法在这种情况下是最好的,那么这个想法的简洁实现。我正在寻找一个理想情况下最不具侵入性的解决方案,并且很容易添加新类。

编辑:我想出了一个解决方法,但它包含了一些冗长(但至少避免了非平凡的代码重复):

struct Base
{
    virtual void doSomething(Output<int>& out) = 0;
    virtual void doSomething(Output<float>& out) = 0;
    virtual void doSomething(Output<double>& out) = 0;

private:
    template<typename T>
    void doSomething(Output<T>& out)
    {
        std::cout << "Base doSomething called with: " << typeid(T).name() << "\n";
    }
};

struct DerivedA : public Base
{
    void doSomething(Output<int>& out) final
    {
        doSomething<int>(out);
    }
    void doSomething(Output<float>& out) final
    {
        doSomething<float>(out);
    }
    void doSomething(Output<double>& out) final
    {
        doSomething<double>(out);
    }
private:
    template<typename T>
    void doSomething(Output<T>& out)
    {
        std::cout << "DerivedA doSomething called with: " << typeid(T).name() << "\n";
    }
};

struct DerivedB : public Base
{
    void doSomething(Output<int>& out) final
    {
        doSomething<int>(out);
    }
    void doSomething(Output<float>& out) final
    {
        doSomething<float>(out);
    }
    void doSomething(Output<double>& out) final
    {
        doSomething<double>(out);
    }
private:
    template<typename T>
    void doSomething(Output<T>& out)
    {
        std::cout << "DerivedB doSomething called with: " << typeid(T).name() << "\n";
    }
};

有没有人能够更好地了解我怎样才能解决这个问题,而不必一遍又一遍地重新定义相同的功能?理想情况下,它将在基类中定义一次,CRTP似乎没有帮助。动态演员似乎是另一个理智的选择。

c++ templates virtual-functions
1个回答
0
投票

尝试这样的事情:

struct OutputBase
{
    virtual void doSomething() = 0;
};

template<class T >
struct Output : public OutputBase
{
    virtual void doSomething()
    {
        std::cout << typeid(T).name();
    }
};


struct Base
{
    virtual void doSomething(OutputBase* out) = 0;
};

struct DerivedA : public Base
{
    virtual void doSomething(OutputBase* out)
    {
        std::cout << "DerivedA doSomething called with: ";
        out->doSomething();
        std::cout<< std::endl;
    }
};

struct DerivedB : public Base
{
    virtual void doSomething(OutputBase* out)
    {
        std::cout << "DerivedB doSomething called with: ";
        out->doSomething();
        std::cout << std::endl;
    }
};
int main()
{
    OutputBase* out_int = new Output < int > ;
    OutputBase* out_double = new Output < double >;
    Base* a = new DerivedA;
    a->doSomething(out_int);
    a->doSomething(out_double);
    Base* b = new DerivedB;
    b->doSomething(out_int);
    b->doSomething(out_double);

    return 0;
}

如果您不想更改它,可以在Output周围使用包装器。

© www.soinside.com 2019 - 2024. All rights reserved.