与C模板的建造者模式

前端之家收集整理的这篇文章主要介绍了与C模板的建造者模式前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个高度可配置的类,有许多模板参数,如下所示:
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,Class2B>.这可能吗?

编辑:向模板参数列表添加了类.

解决方法

正如其他人所说,做你想做的最简单的方法是使用enum而不是Builder.但是,如果你想要一个Builder,你可以尝试这样的事情:
template<bool OptionA = 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,T>          { return {}; }
    auto uSEOptionC() -> Builder_t<OptionA,T>          { return {}; }
    auto useClass2B() -> Builder_t<OptionA,Class2B> { return {}; }

    MyClass<OptionA,T> create() { return {}; }
};
using Builder = Builder_t<>;

// ...

// Build MyClass<true,false,Class2B>:
auto ma2 = Builder{}.uSEOptionA().useClass2B().create();

这会导致每个函数返回一个不同的Builder,其模板将被下一个函数使用;最终模板用作MyClass的模板.每个函数修改其指定的模板参数,允许编译时版本的Builder模式.但是,它确实有成本,如果取消注释用户定义的析构函数,这一点就变得很明显了.

考虑这个简单的测试程序:

#include <iostream>
#include <typeinfo>

class Class1B {};
class Class2B {};

template<bool OptionA = false,typename T = Class1B>
class MyClass
{
  public:
    MyClass() {
        std::cout << "MyClass<"
                  << OptionA << ","
                  << OptionB << ","
                  << OptionC << ","
                  << "type " << typeid(T).name() << ">"
                  << std::endl;
    }
};

template<bool OptionA = false,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,type 7Class1B>
Builder: MyClass<false,type 7Class1B>

Builder pattern:
A: MyClass<true,type 7Class1B>
C: MyClass<false,type 7Class1B>
---
AB: MyClass<true,type 7Class1B>
B2: MyClass<false,type 7Class2B>
---
ABC: MyClass<true,type 7Class1B>
AC2: MyClass<true,type 7Class2B>
---
ABC2: MyClass<true,type 7Class2B>

但是,如果我们取消注释析构函数……

Default:
Direct:  MyClass<false,type 7Class1B>
Builder dtor.

Builder pattern:
A: MyClass<true,type 7Class1B>
Builder dtor.
Builder dtor.
C: MyClass<false,type 7Class1B>
Builder dtor.
Builder dtor.
---
AB: MyClass<true,type 7Class1B>
Builder dtor.
Builder dtor.
Builder dtor.
B2: MyClass<false,type 7Class2B>
Builder dtor.
Builder dtor.
Builder dtor.
---
ABC: MyClass<true,type 7Class1B>
Builder dtor.
Builder dtor.
Builder dtor.
Builder dtor.
AC2: MyClass<true,type 7Class2B>
Builder dtor.
Builder dtor.
Builder dtor.
Builder dtor.
---
ABC2: MyClass<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,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,T>          { return {}; }
    constexpr auto uSEOptionB() -> Builder_t<OptionA,T>          { return {}; }
    constexpr auto uSEOptionC() -> Builder_t<OptionA,T>          { return {}; }
    constexpr auto useClass2B() -> Builder_t<OptionA,Class2B> { return {}; }

    constexpr MyClass<OptionA,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';
原文链接:https://www.f2er.com/c/119709.html

猜你在找的C&C++相关文章