我正在努力将模板编程(以及在未来的某个时间点,模板元编程)应用到现实世界的场景中。我发现的一个问题是 C++ 模板和多态性并不总是以我想要的方式一起使用。
我的问题是我尝试应用模板编程的方式是否不正确(我应该使用普通的旧 OOP),或者我是否仍然停留在 OOP 思维模式中。
在这种特殊情况下,我正在尝试使用策略模式来解决问题。我一直遇到这样的问题,我最终想要一些模板似乎不支持的多态行为。
使用组合的 OOP 代码:
class Interpolator {
public:
Interpolator(ICacheStrategy* const c, IDataSource* const d);
Value GetValue(const double);
}
void main(...) {
Interpolator* i;
if(param==1)
i = new Interpolator(new InMemoryStrategy(...), new TextFileDataSource(...));
else if(param==2)
i = new Interpolator(new InMemoryStrategy(...), new OdbcDataSource(...));
else if(param==3)
i = new Interpolator(new NoCachingStrategy(...), new RestDataSource(...));
while(run) {
double input = WaitForRequest();
SendRequest( i->GetValue(input));
}
}
潜在的模板版本:
class Interpolator<class TCacheStrategy, class TDataSource> {
public:
Interpolator();
Value GetValue(const double); //may not be the best way but
void ConfigCache(const& ConfigObject); //just to illustrate Cache/DS
void ConfigDataSource(const& ConfigObject); //need to configured
}
//Possible way of doing main?
void main(...) {
if(param==1)
DoIt(Interpolator<InMemoryStrategy,TextFileDataSource>(),c,d);
else if(param==2)
DoIt(Interpolator<InMemoryStrategy,OdbcDataSource>(),c,d)
else if(param==3)
DoIt(Interpolator<NoCachingStrategy,RestDataSource>(),c,d)
}
template<class T>
void DoIt(const T& t, ConfigObject c, ConfigObject d) {
t.ConfigCache(c);
t.ConfigDataSource(c);
while(run) {
double input = WaitForRequest();
SendRequest( t.GetValue(input));
}
}
当我尝试将 OOP 实现转换为基于模板的实现时,可以轻松翻译 Interpolator 代码。基本上,用模板类型参数替换“接口(interface)”,并添加一种机制来传递策略/数据源的实例或配置参数。
但是当我谈到“主要”时,我不清楚应该如何编写以利用模板元编程风格的模板。我经常想使用多态,但它似乎不能很好地与模板一起使用(有时,感觉就像我需要 Java 的类型删除泛型......呃)。
当我经常发现我想做的事情是 TemplateType<?,?> x = new TemplateType<X,Y>()其中 x 不在乎 X,Y 是什么。
其实这是我在使用模板时经常遇到的问题。
[编辑] 一些人指出这实际上不是模板元编程,所以我稍微改写了这个问题。也许这就是问题的一部分——我还没有弄清楚 TMP 到底是什么。
最佳答案
模板提供静态多态性:您在编译时指定模板参数来实现策略。它们不提供动态多态性,您在运行时为对象提供实现策略的虚拟成员函数。
您的示例模板代码将创建三个不同的类,每个类都包含所有插值器代码,使用不同的模板参数进行编译,并可能从它们内联代码。从代码大小的 POV 来看,这可能不是您想要的,尽管它绝对没有错。假设您正在优化以避免函数调用开销,那么它可能是对动态多态性的改进。更有可能是矫枉过正。如果您想动态使用策略模式,则不需要模板,只需在相关的地方进行虚拟调用。
您不能有 MyTemplate<?> 类型的变量(除非在实例化之前出现在另一个模板中)。 MyTemplate<X>和 MyTemplate<Y>是完全不相关的类(即使 X 和 Y 是相关的),如果它们是从同一个模板实例化的,它们可能恰好具有相似的功能(它们不必是 - 一个可能是专门化的)。即使它们是,如果模板参数涉及任何成员函数的签名,那么这些函数也不相同,它们只是具有相同的名称。所以从动态多态的观点来看,同一个模板的实例与任何两个类都处于相同的位置——只有给它们一个带有一些虚成员函数的公共(public)基类,它们才能发挥作用。
所以,你可以定义一个通用的基类:
class InterpolatorInterface {
public:
virtual Value GetValue(const double) = 0;
virtual void ConfigCache(const& ConfigObject) = 0;
virtual void ConfigDataSource(const& ConfigObject) = 0;
virtual ~InterpolatorInterface() {}
};
然后:
template <typename TCacheStrategy, typename TDataSource>
class Interpolator: public InterpolatorInterface {
...
};
现在您正在使用模板根据编译时已知的内容创建不同类型的插值器(因此从插值器到策略的调用是非虚拟的),并且您正在使用动态多态性对它们进行相同处理即使您直到运行时才知道您想要哪一个(因此从客户端到插值器的调用是虚拟的)。您只需要记住,这两种技术几乎是完全独立的技术,而使用每种技术的决定几乎没有关系。
顺便说一句,这不是模板元编程,它只是使用模板。
编辑。至于什么是 TMP,下面是典型的介绍性示例:
#include <iostream>
template<int N>
struct Factorial {
static const int value = N*Factorial<N-1>::value;
};
template<>
struct Factorial<0> {
static const int value = 1;
};
int main() {
std::cout << "12! = " << Factorial<12>::value << "\n";
}
注意那 12 个!已由编译器计算,并且是编译时常量。这是令人兴奋的,因为事实证明 C++ 模板系统是图灵完备的编程语言,而 C 预处理器不是。受限于资源限制,您可以在编译时进行任意计算,避免在编译时知道输入的情况下的运行时开销。模板可以像函数式语言一样操作其模板参数,模板参数可以是整数或类型。或函数,尽管在编译时不能“调用”这些函数。或其他模板,尽管它们不能作为结构的静态成员“返回”。
关于c++ - 模板多态可以代替OO多态吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1213366/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的
我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI
我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:
我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的rubyyaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir