C++ 虚拟模板函数的替代方案
我有一个抽象的C++ 虚拟模板函数的替代方案,c++,templates,inheritance,polymorphism,virtual,C++,Templates,Inheritance,Polymorphism,Virtual,我有一个抽象的UI类,它需要能够向用户请求一些输入。 此函数是模板化的,因为可以要求不同的内容 但是,这个函数也必须是虚拟的,因为我希望UI的派生类能够 提供自己的实现(aCommandLineUI需要与 WebBasedUI) 类用户界面{ // ... 公众: //询问一些意见 模板 虚拟T askFor(const std::string&mesg)const=0; //询问但提供默认回退 模板 虚拟T askFor(常数std::string&mesg,常数T&def)常数=0; } 类
UI
类,它需要能够向用户请求一些输入。
此函数是模板化的,因为可以要求不同的内容
但是,这个函数也必须是虚拟的,因为我希望UI
的派生类能够
提供自己的实现(aCommandLineUI
需要与
WebBasedUI
)
类用户界面{
// ...
公众:
//询问一些意见
模板
虚拟T askFor(const std::string&mesg)const=0;
//询问但提供默认回退
模板
虚拟T askFor(常数std::string&mesg,常数T&def)常数=0;
}
类CommandLineUI:UI{
// ...
公众:
模板
虚拟T askFor(const std::string&mesg)const{
//实施细节
}
模板
虚拟T askFor(常数std::string&mesg,常数T&def)常数{
//实施细节
}
}
<>上述代码将无法工作,因为模板化方法不能在C++中是虚拟的,
因为我无法理解的原因
我读过一些关于访问者模式或类型擦除能够解决此问题的文章,但我不知道如何解决。(我试着翻译答案中的例子
类似的堆栈溢出问题,但没有成功。)在这种情况下,标准非常简单 §14.5.2.3)成员功能模板不得是虚拟的。[示例:
模板结构AA{
模板虚空g(C);//错误
虚拟void f();//确定
};
-[结束示例]
基本上,您将如何实现它们?vtable看起来像什么
如果您只需要一个“可流化”的类型,我建议您查看库。它可能不能完全解决你的问题,但它相当整洁。您将需要以下内容:
using Inputable = any<
mpl::vector<
copy_constructible<>,
typeid_<>,
istreamable<>
>
>;
virtual Inputable askFor(const std::string& mesg) const = 0;
使用Inputable=any<
向量<
可构造的副本,
typeid_2;,
可扩展
>
>;
虚拟可输入askFor(const std::string&mesg)const=0;
可能比这更复杂,我只使用了这个库,但它可以让你有一个虚拟的“模板”成员函数,只要你清楚地定义你需要模板类型做什么。(请注意,还有一个
any_cast
,因此调用者知道他想要得到什么类型,他总是可以将结果投射到它。)根据您的评论,我建议为界面提供一系列虚拟函数,用于您想要支持的有限类型集。在派生类中,您可以将每个重写函数的调用转发到实现所需功能的单个模板函数。模板函数不能是虚拟的
。虚拟函数不能是模板,因为在编译时必须知道重载的数量。但是,如果在代码中的某个地方执行ui.askFor()
,则在不同编译单元中创建的对象的vtable将丢失该条目。这里的问题是,您试图混合使用运行时和编译时多态。为什么不定义一组受支持的类型?通常情况下,你可以很好地使用int、float、string、datetime、它们的列表、它们的字典等集合。看起来你并没有认真考虑这个设计。您将如何为实现命令行ui::ask?当我调用ui->askFor(“输入frobnitator:”)
时会发生什么?askFor
适用于流中可以读取的所有内容。为int
、double
、string
等编写自定义函数的问题在于,实现代码会非常重复,而且askFor
函数非常复杂。。。
template <class T> struct AA {
template <class C> virtual void g(C); // error
virtual void f(); // OK
};
using Inputable = any<
mpl::vector<
copy_constructible<>,
typeid_<>,
istreamable<>
>
>;
virtual Inputable askFor(const std::string& mesg) const = 0;