需要为虚函数的模板返回类型

Template return type of a function that needs to be virtual

本文关键字:返回类型 函数      更新时间:2023-10-16

因为以下内容是非法的:

struct A {
    template <typename T>
    virtual T* foo() = 0;
};
struct B : A {
    template <typename T>
    virtual T* foo() override {return new T;}  // Simple example here.
};
template <typename T>
T* bar (A* a) {
    return a->foo<T>();  // The need for the virtual method.
}

和模板只出现在返回类型中,我想到了一个(naïve?)的解决方案,使用重载:

#include <iostream>
struct Base { virtual void show() const = 0; };
struct Object : Base { virtual void show() const override {std::cout << "I am an Object.n";} };
struct Thing : Base { virtual void show() const override {std::cout << "I am a Thing.n";} };
struct Blob : Base { virtual void show() const override {std::cout << "I am a Blob.n";} };
struct A {
    virtual Object* foo (Object&&) = 0;
    virtual Thing* foo (Thing&&) = 0;
    virtual Blob* foo (Blob&&) = 0;
};
struct B : A {
    virtual Object* foo (Object&&) override {return fooHelper<Object>();}
    virtual Thing* foo (Thing&&) override {return fooHelper<Thing>();}
    virtual Blob* foo (Blob&&) override {return fooHelper<Blob>();}
private:
    template <typename T>
    T* fooHelper() {return new T;}  // Simple example here.
};
template <typename T>
T* bar (A* a) {
    return a->foo(T{});
}
int main() {
    B* b = new B;
    Base* list[] = {bar<Object>(b), bar<Thing>(b), bar<Blob>(b)};
    for (const Base* x : list) x->show();
}

这个解决方案的问题是,它只有在T没有太多类型的情况下才可行。但如果有呢?此外,当稍后引入T的新类型时,现在存在维护问题。

有人能想出比这更好的解决办法吗?作为虚拟模板解决方案的已知访问者模式在这里不适用(我不认为),因为模板没有出现在参数中。
...
    T* fooHelper() {return new T;}
};
template <typename T>
T* create (A* a) {
    return a->foo(T{});
}

A的实例对返回的T没有影响。我想这应该是一个论点。你好像还想要一个工厂。如何使用成员函数:

template < typename T, typename FactoryType, 
           typename MemFnType, typename ArgType >
T* create(FactoryType* f, MemFnType mfn, ArgType a)
{
    return (f->*mfn)(a);
}

完整的示例:

#include <iostream>
struct Base { virtual void show() const = 0; };
struct Object : Base { virtual void show() const override {std::cout << "I am an Object.n";} };
struct Thing : Base { virtual void show() const override {std::cout << "I am a Thing.n";} };
struct Blob : Base { virtual void show() const override {std::cout << "I am a Blob.n";} };
struct Args
{
    int someArg;
};
struct Factory
{
    // normally 'a' would be passed to the Object constructor.
    // omitted to save edits.
    Object* asObject(const Args& a) { return new Object(); }
    Thing* asThing(const Args& a) { return new Thing(); }
    Blob* asBlob(const Args& a) { return new Blob(); }
};
template < typename T, typename FactoryType, 
           typename MemFnType, typename ArgType >
T* create(FactoryType& f, MemFnType mfn, ArgType& a)
{
    return (&f->*mfn)(a);
}
int main() {
    Args arg;
    Factory f;
    Base* list[] = {create<Object>(f, &Factory::asObject, arg), create<Thing>(f, &Factory::asThing, arg), create<Blob>(f, &Factory::asBlob, arg)};
    for (const Base* x : list) x->show();
}
添加可构造类型只需要添加类型本身和相关的工厂函数。你甚至可以将它泛化为一个完整的模板参数列表,而不是单一的参数类型。