【问题标题】:Alternative for virtual template functions虚拟模板功能的替代方案
【发布时间】:2015-01-04 03:28:38
【问题描述】:

我有一个抽象的UI 类,它需要能够向用户询问一些输入。 这个函数是模板化的,因为可以要求不同的东西。

但是,这个函数也必须是虚拟的,因为我希望 UI 的派生类能够 提供他们自己的实现(CommandLineUI 的行为需要与 WebBasedUI)。

class UI {
    // ...

    public:
        // ask some input
        template<T>
        virtual T askFor(const std::string& mesg) const = 0;

        // ask but provide default fallback
        template<T>
        virtual T askFor(const std::string& mesg, const T& def) const = 0;
}

class CommandLineUI : UI {
    // ...
    public:
        template<T>
        virtual T askFor(const std::string& mesg) const {
            // implementation details
        }
        template<T>
        virtual T askFor(const std::string& mesg, const T& def) const {
            // implementation details
        }
}

然而,上面的代码不起作用,因为模板化的方法在 C++ 中不能是虚拟的, 出于我上面的原因。

我阅读了一些关于访问者模式或类型擦除能够解决此问题的内容,但我不知道如何解决。 (我试图将答案中找到的示例翻译为 类似的堆栈溢出问题,但没有成功)。

【问题讨论】:

  • 模板函数不能为virtual
  • 虚函数不能是模板,因为在编译时必须知道重载的数量。但是,如果您在某处的代码中执行 ui.askFor&lt;not_yet_used_type&gt;(),则在不同编译单元中创建的对象的 vtable 将丢失该条目。
  • 这里的问题是你试图混合运行时和编译时多态性。为什么不定义一组支持的类型?通常,您可以很好地使用 int、float、string、datetime、它们的列表、它们的字典之类的集合。
  • 看来您并没有真正考虑过这个设计。你将如何实现CommandLineUI::askFor?当我拨打ui-&gt;askFor&lt;Frobnicator&gt;("Enter frobnicator:") 时会发生什么?
  • askFor 适用于可以从流中读取的所有内容。为intdoublestring等编写自定义函数的问题是实现代码会非常重复,askFor函数真的很复杂……

标签: c++ templates inheritance polymorphism virtual


【解决方案1】:

根据您的 cmets,我建议为接口提供一系列虚函数,用于您想要支持的有限类型集。在派生类中,您可以将每个重写函数的调用转发到实现所需功能的单个模板函数。

【讨论】:

    【解决方案2】:

    在这种情况下,标准非常简单

    §14.5.2.3) 成员函数模板不应是虚拟的。 [ 例子:

    template <class T> struct AA {
        template <class C> virtual void g(C); // error
        virtual void f(); // OK
    };
    

    ——结束示例 ]

    基本上,您将如何实现它们? vtable 会是什么样子?

    如果您只需要一种“可流式传输”的类型,我建议您查看Boost.TypeErasure 库。它可能不能完全解决您的问题,但它非常整洁。你需要类似的东西:

    using Inputable = any<
        mpl::vector<
            copy_constructible<>,
            typeid_<>,
            istreamable<>
        >
    >;
    
    virtual Inputable askFor(const std::string& mesg) const = 0;
    

    可能比这更复杂,我只玩过那个库,但是只要你清楚地定义你需要你的模板类型做什么,它就可以拥有一个虚拟的“模板”成员函数。 (请注意,还有一个any_cast,所以调用者知道他想要得到什么类型,他总是可以将结果转换为它。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-01
      • 1970-01-01
      • 2011-02-12
      • 1970-01-01
      相关资源
      最近更新 更多