最近我一直在考虑如何设计一个特定的软件,有一次我制作了以下部分:
template <typename ... Mixins>
class Foo : public virtual Mixins... {
/* ... */
};
我的想法是能够根据用户的需要使用额外的属性或行为来扩充基本类。假设一个应用程序需要使用带有标识号的 Foo。也许其他一些应用程序需要能够用颜色来谈论 Foo。这些需求可以通过添加以下类来满足:
class HasID {
int m_id = -1;
public:
int getID() { return m_id; }
void assignID(int id) { m_id = id; }
};
class HasColor {
public:
int color = 0;
};
我对这段代码的两个问题如下:
这是一个额外的示例,展示了打印增强类对象的详细信息的可能性。
打印函数:
// Default printBase
template <typename Base>
void printBase(std::ostream& out, Base& x) {}
// printBase for HasID
template <>
void printBase(std::ostream& out, HasID& x) {
out << ", ID=" << x.getID();
}
// printBase for HasColor
template <>
void printBase(std::ostream& out, HasColor& x) {
out << ", color=" << x.color;
}
// Recursive step of printBases
template <typename Derived, typename Base, typename ... Bases>
void printBases(std::ostream& out, Derived& x, Base& y) {
printBase(out, y);
printBases<Derived, Bases...>(out, x, x);
}
// Base case of printBases
template <typename Derived>
void printBases(std::ostream& out, Derived& x, Derived& y) {}
// ostream operator
template <typename ... Mixins>
std::ostream& operator<<(std::ostream& out, Foo<Mixins...>& x) {
out << "<Foo";
printBases<Foo<Mixins...>, Mixins...>(out, x, x);
return out << '>';
}
主要内容:
int main()
{
Foo<> plainFoo;
Foo<HasID> fooWithID;
fooWithID.assignID(42);
Foo<HasID, HasColor> multiTalentedFoo;
multiTalentedFoo.assignID(1234);
multiTalentedFoo.color = 0xff0000;
std::cout
<< plainFoo << '\n'
<< fooWithID << '\n'
<< multiTalentedFoo << '\n';
}
输出:
<Foo>
<Foo, ID=42>
<Foo, ID=1234, color=16711680>
最佳答案
My two questions about this code are as follows:
Does this particular pattern have a name?
What are the uses and drawbacks of using templates like this?
CRTP“奇怪的重复模板模式”或有时也称为“mixin”。
https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
当网络知道这种模式/习语时,我们真的要在这里再次讨论缺点吗?讨论得够多了:-)
https://softwareengineering.stackexchange.com/questions/123886/is-crtp-used-much-and-why-it-is-isnt
本文http://www.drdobbs.com/building-more-flexible-types-with-mixins/184402056备注:
The biggest drawback of the CRTP technique is that constructors aren't inherited. This means that if you use an initializing constructor in your implementation class, every extension will have to have an appropriate initializing constructor. This causes the extensions to be more restricted and, as such, less useful.
对于 c++14 来说,这不再是正确的,你有很好的机会用可变参数模板和基类的构造函数调用链来消除这个论点。继承和委派构造函数也有助于实现这一目的。
与所有模板一样,您必须记住每个实例化都是一个新类型,这会导致您的可执行文件中出现大量代码重复。我经常使用这种模式并接受成本。另一种方法是手工制作可执行文件大小不少的代码。你必须为你需要的东西付费。
关于c++ - 指定类基类的 C++ 模板参数的用途和缺点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38605329/
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我的瘦服务器配置了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_”……这
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat