实现Builder forFoo
的标准方法是这样的:
class Foo::Builder {
public:
Builder& setBar(bool bar);
...
Foo build() const;
};
仅当调用方尝试将此类与智能指针一起使用时:
auto builder = std::make_shared<Foo::Builder>()->setProperty(...);
生成器不能以这种方式使用,因为setProperty()
将返回对对象的引用,该对象将在此语句完成执行时被销毁。当调用方在同一语句中调用build()
并且Builder
类永远不会绑定到变量名时,这无关紧要。
但是,在我的应用程序中,我希望能够在派生的构建器对象上进行一些配置,然后将其传递给另一个类的构造函数(该构造函数将其作为指向基类型的指针接收(。我还希望调用者能够决定所用指针的类型。我可以通过Foo::Builder
模板来做到这一点吗?有没有更好的设计模式更适合这一点?我对想法持开放态度。
控制其他人用来指向实例的内容不是类业务。如果另一个类在其构造函数中接收到指向Builder
的指针,则可以使构造函数成为模板:
struct OtherClass {
template <typename T>
OtherClass(T t) {
t->setProperty();
}
};
如果要将T
限制为具有返回Builder
的operator->
的类型,则可以等待C++20概念,也可以编写允许SFINAE的类型特征:
template <typename P,typename T>
struct points_to : std::false_type {};
template <typename T>
struct points_to<T*,T> : std::true_type {};
template <typename P>
struct points_to<P,std::decay_t<decltype(std::declval<P>().operator->())>> : std::true_type {};
然后,构造函数可以通过以下方式要求points_to<T,Builder>
:
struct AnotherClass {
template <typename T,typename = std::enable_if_t<points_to<T,Builder>::value,void>>
AnotherClass(T t){}
};
但是,错误消息不会比上面的非受限模板好多少。static_assert
有助于获取可读的错误消息:
struct AnotherClass {
template <typename B>
AnotherClass(B b){
static_assert(points_to<B,Builder>::value,"b is not pointing to a Builder");
}
};
现场示例