我有一个高度可配置的类,其中包含许多模板参数,如下所示:
template<bool OptionA = false, bool OptionB = false, bool OptionC = false, class T = Class1B>
class MyClass
{
}
现在,如果我想创建类类型并且我只想将 OptionB 设置为 true,我必须执行以下操作:
MyClass<false, true>
特别是对于许多模板参数,这会变得很麻烦。
不,我的问题是,是否有任何示例可用于使用构建器模式创建基于模板的类类型?
我正在寻找这样的东西:
class Builder
{
useOptionA();
useOptionB();
useOptionC();
useClass2B(); //instead of Class1B
create();
}
最后调用 Builder.useOptionB().useOptionC().useClass2B.create()应该返回 MyClass<false, true, true, Class2B> .这可能吗?
编辑:将类添加到模板参数列表。
最佳答案
正如其他人所说,最简单的方法是使用 enum 而不是 Builder。但是,如果您确实想要一个 Builder,您可以尝试这样的事情:
template<bool OptionA = false,
bool OptionB = false,
bool OptionC = false,
typename T = Class1B>
struct Builder_t
{
Builder_t() = default;
// ~Builder_t() { std::cout << "Builder dtor." << std::endl; }
auto useOptionA() -> Builder_t<true, OptionB, OptionC, T> { return {}; }
auto useOptionB() -> Builder_t<OptionA, true, OptionC, T> { return {}; }
auto useOptionC() -> Builder_t<OptionA, OptionB, true, T> { return {}; }
auto useClass2B() -> Builder_t<OptionA, OptionB, OptionC, Class2B> { return {}; }
MyClass<OptionA, OptionB, OptionC, T> create() { return {}; }
};
using Builder = Builder_t<>;
// ...
// Build MyClass<true, false, false, Class2B>:
auto ma2 = Builder{}.useOptionA().useClass2B().create();
这会导致每个函数返回一个不同的Builder,其模板将被下一个函数使用;最终模板用作 MyClass 的模板。每个函数都会修改其指定的模板参数,从而允许生成器模式的编译时版本。不过,它确实有成本,如果取消注释用户定义的析构函数,这一点就会变得很明显。
考虑这个简单的测试程序:
#include <iostream>
#include <typeinfo>
class Class1B {};
class Class2B {};
template<bool OptionA = false,
bool OptionB = false,
bool OptionC = false,
typename T = Class1B>
class MyClass
{
public:
MyClass() {
std::cout << "MyClass<"
<< OptionA << ", "
<< OptionB << ", "
<< OptionC << ", "
<< "type " << typeid(T).name() << ">"
<< std::endl;
}
};
template<bool OptionA = false,
bool OptionB = false,
bool OptionC = false,
typename T = Class1B>
struct Builder_t
{
Builder_t() = default;
// ~Builder_t() { std::cout << "Builder dtor." << std::endl; }
auto useOptionA() -> Builder_t<true, OptionB, OptionC, T> { return {}; }
auto useOptionB() -> Builder_t<OptionA, true, OptionC, T> { return {}; }
auto useOptionC() -> Builder_t<OptionA, OptionB, true, T> { return {}; }
auto useClass2B() -> Builder_t<OptionA, OptionB, OptionC, Class2B> { return {}; }
MyClass<OptionA, OptionB, OptionC, T> create() { return {}; }
};
using Builder = Builder_t<>;
int main()
{
std::cout << std::boolalpha;
std::cout << "Default:\n";
std::cout << "Direct: ";
MyClass<> m;
std::cout << "Builder: ";
auto mdefault = Builder{}.create();
std::cout << std::endl;
std::cout << "Builder pattern:\n";
std::cout << "A: ";
auto ma = Builder{}.useOptionA().create();
std::cout << "C: ";
auto mc = Builder{}.useOptionC().create();
std::cout << "---\n";
std::cout << "AB: ";
auto mab = Builder{}.useOptionA().useOptionB().create();
std::cout << "B2: ";
auto mb2 = Builder{}.useOptionB().useClass2B().create();
std::cout << "---\n";
std::cout << "ABC: ";
auto mabc = Builder{}.useOptionA().useOptionB().useOptionC().create();
std::cout << "AC2: ";
auto mac2 = Builder{}.useOptionA().useOptionC().useClass2B().create();
std::cout << "---\n";
std::cout << "ABC2: ";
auto mabc2 = Builder{}.useOptionA().useOptionB().useOptionC().useClass2B().create();
}
正常情况下,输出如下(使用GCC):
Default:
Direct: MyClass<false, false, false, type 7Class1B>
Builder: MyClass<false, false, false, type 7Class1B>
Builder pattern:
A: MyClass<true, false, false, type 7Class1B>
C: MyClass<false, false, true, type 7Class1B>
---
AB: MyClass<true, true, false, type 7Class1B>
B2: MyClass<false, true, false, type 7Class2B>
---
ABC: MyClass<true, true, true, type 7Class1B>
AC2: MyClass<true, false, true, type 7Class2B>
---
ABC2: MyClass<true, true, true, type 7Class2B>
但是,如果我们取消注释析构函数...
Default:
Direct: MyClass<false, false, false, type 7Class1B>
Builder: MyClass<false, false, false, type 7Class1B>
Builder dtor.
Builder pattern:
A: MyClass<true, false, false, type 7Class1B>
Builder dtor.
Builder dtor.
C: MyClass<false, false, true, type 7Class1B>
Builder dtor.
Builder dtor.
---
AB: MyClass<true, true, false, type 7Class1B>
Builder dtor.
Builder dtor.
Builder dtor.
B2: MyClass<false, true, false, type 7Class2B>
Builder dtor.
Builder dtor.
Builder dtor.
---
ABC: MyClass<true, true, true, type 7Class1B>
Builder dtor.
Builder dtor.
Builder dtor.
Builder dtor.
AC2: MyClass<true, false, true, type 7Class2B>
Builder dtor.
Builder dtor.
Builder dtor.
Builder dtor.
---
ABC2: MyClass<true, true, true, type 7Class2B>
Builder dtor.
Builder dtor.
Builder dtor.
Builder dtor.
Builder dtor.
Builder_t::create() 之前的每次调用都会创建一个不同的 Builder_t,所有这些都会在实例创建后销毁。这可以通过将 Builder_t 设为 constexpr 类来缓解,但如果有大量参数需要处理,这可能会减慢编译速度:
template<bool OptionA = false,
bool OptionB = false,
bool OptionC = false,
typename T = Class1B>
struct Builder_t
{
// Uncomment if you want to guarantee that your compiler treats Builder_t as constexpr.
// size_t CompTimeTest;
constexpr Builder_t()
// Uncomment if you want to guarantee that your compiler treats Builder_t as constexpr.
// : CompTimeTest((OptionA ? 1 : 0) +
// (OptionB ? 2 : 0) +
// (OptionC ? 4 : 0) +
// (std::is_same<T, Class2B>{} ? 8 : 0))
{}
constexpr auto useOptionA() -> Builder_t<true, OptionB, OptionC, T> { return {}; }
constexpr auto useOptionB() -> Builder_t<OptionA, true, OptionC, T> { return {}; }
constexpr auto useOptionC() -> Builder_t<OptionA, OptionB, true, T> { return {}; }
constexpr auto useClass2B() -> Builder_t<OptionA, OptionB, OptionC, Class2B> { return {}; }
constexpr MyClass<OptionA, OptionB, OptionC, T> create() { return {}; }
};
using Builder = Builder_t<>;
// ....
// Uncomment if you want to guarantee that your compiler treats Builder_t as constexpr.
// char arr[Builder{}/*.useOptionA()/*.useOptionB()/*.useOptionC()/*.useClass2B()/**/.CompTimeTest];
// std::cout << sizeof(arr) << '\n';
关于c++ - 带有 C++ 模板的构建器模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40071779/
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我的瘦服务器配置了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_”……这
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
在编写Ruby(客户端脚本)时,我看到了三种构建更长字符串的方法,包括行尾,所有这些对我来说“闻起来”有点难看。有没有更干净、更好的方法?变量递增。ifrender_quote?quote="NowthatthereistheTec-9,acrappyspraygunfromSouthMiami."quote+="ThisgunisadvertisedasthemostpopularguninAmericancrime.Doyoubelievethatshit?"quote+="Itactuallysaysthatinthelittlebookthatcomeswithit:themo
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
我正在使用Mandrill的RubyAPIGem并使用以下简单的测试模板:testastic按照Heroku指南中的示例,我有以下Ruby代码:require'mandrill'm=Mandrill::API.newrendered=m.templates.render'test-template',[{:header=>'someheadertext',:main_section=>'Themaincontentblock',:footer=>'asdf'}]mail(:to=>"JaysonLane",:subject=>"TestEmail")do|format|format.h
所以这可能有点令人困惑,但请耐心等待。简而言之,我想遍历具有特定键值的所有属性,然后如果值不为空,则将它们插入到模板中。这是我的代码:属性:#===DefaultfileConfigurations#default['elasticsearch']['default']['ES_USER']=''default['elasticsearch']['default']['ES_GROUP']=''default['elasticsearch']['default']['ES_HEAP_SIZE']=''default['elasticsearch']['default']['MAX_OP