模板 boost::factory
允许您将 new
表达式封装为函数对象,boost::value_factory
封装了不带 new
的构造函数调用。
boost::factory
<T*>()(arg1,arg2,arg3) // same as new T(arg1,arg2,arg3)boost::value_factory
<T>()(arg1,arg2,arg3) // same as T(arg1,arg2,arg3)
在 C++11 之前,函数对象的实参必须是左值。可以使用 boost::forward_adapter
或 boost::bind
组成一个也接受右值的工厂。在 C++11 或更高版本中,实参可以是左值或右值。
在传统的面向对象编程中,工厂是一个对象,它实现了一个或多个方法的接口,这些方法构造符合已知接口的对象。
// assuming a_concrete_class and another_concrete_class are derived // from an_abstract_class struct a_factory { virtual an_abstract_class* create() const = 0; virtual ~a_factory() { } }; struct a_concrete_factory : a_factory { an_abstract_class* create() const { return new a_concrete_class(); } }; struct another_concrete_factory : a_factory { an_abstract_class* create() const { return new another_concrete_class(); } }; // [...] int main() { boost::ptr_map<std::string, a_factory> factories; // [...] factories.insert("a_name", std::unique_ptr<a_factory>(new a_concrete_factory)); factories.insert("another_name", std::unique_ptr<a_factory>(new another_concrete_factory)); // [...] std::unique_ptr<an_abstract_class> x(factories.at(some_name).create()); // [...] }
这种方法有几个缺点。最明显的一个是存在大量的样板代码。换句话说,用太多的代码来表达一个相当简单的意图。我们可以使用模板来去除其中的一些代码,但这种方法仍然缺乏灵活性。
new
在堆栈上创建对象,并且经验表明,使用函数对象和通用的 Boost 组件来组合它们,描述回调机制的设计模式(通常需要使用纯面向对象方法编写大量的样板代码)只需几行代码即可实现,而无需额外的类。
工厂是构造函数的回调机制,因此我们提供了两个类模板,boost::value_factory
和 boost::factory
,它们分别通过直接应用构造函数和 new
运算符来封装对象构造。
我们让函数对象将其参数转发到它们封装的构造表达式。在此基础上,boost::factory
可选择使用智能指针和分配器。
可以在适当的地方使用编译时多态,
template<class T> void do_something() { // [...] T x = T(a, b); // for conceptually similar objects x we neither need virtual // functions nor a common base class in this context. // [...] }
现在,为了允许为 T
传入的类型的构造函数使用不均匀的签名,我们可以使用 value_factory
和 boost::bind
在它们之间进行规范化。
template<class ValueFactory> void do_something(ValueFactory make_obj = ValueFactory()) { // [...] typename ValueFactory::result_type x = make_obj(a, b); // for conceptually similar objects x we neither need virtual // functions nor a common base class in this context. // [...] } int main() { // [...] do_something(boost::value_factory<X>()); do_something(boost::bind(boost::value_factory<Y>(), _1, 5, _2)); // construct X(a, b) and Y(a, 5, b), respectively. // [...] }
也许我们希望我们的对象比函数的作用域更长久,在这种情况下,我们必须使用动态分配;
template<class Factory> whatever do_something(Factory new_obj = Factory()) { typename Factory::result_type ptr = new_obj(a, b); // again, no common base class or virtual functions needed, // we could enforce a polymorphic base by writing e.g. // boost::shared_ptr<base> // instead of // typename Factory::result_type // above. // Note that we are also free to have the type erasure happen // somewhere else (e.g. in the constructor of this function's // result type). // [...] } // [... call do_something like above but with boost::factory instead // of boost::value_factory]
虽然我们可能在前面的例子中创建了多态对象,但我们对工厂使用了编译时多态。如果我们想消除工厂的类型,从而允许在运行时进行多态,我们可以使用 Boost.Function 来实现。第一个例子可以改写如下。
typedef boost::function<an_abstract_class*()> a_factory; // [...] int main() { std::map<std::string, a_factory> factories; // [...] factories["a_name"] = boost::factory<a_concrete_class*>(); factories["another_name"] = boost::factory<another_concrete_class*>(); // [...] }
当然,我们可以很容易地创建接受参数和/或返回 智能指针 的工厂。
调用类型 T
的构造函数的函数对象模板。
#include <boost/functional/value_factory.hpp>
namespace boost { template<class T> class value_factory; } // boost
符号
T
至少有一个公共构造函数的任意类型
a0
...aN
T
的构造函数的实参值
F
类型 value_factory<F>
f
F
的实例对象
表达式 |
语义 |
---|---|
|
创建类型为 |
|
创建类型为 |
|
返回 |
|
是类型 |
在 C++11 之前,支持的参数最大数量为 10。从 C++11 开始,支持任意数量的参数。
函数对象模板,为作为模板参数给出的指针类型动态构造一个指针对象。智能指针可以用于模板参数,前提是 pointer_traits<Pointer>::element_type
产生指针类型。
如果给定一个 分配器,则将其用于内存分配,并使用 new
运算符的放置形式来构造对象。调用析构函数并使用分配器的副本释放内存的函数对象用于 Pointer
的第二个构造函数参数(因此它必须是一个提供合适构造函数的 智能指针,例如 boost::shared_ptr
)。
如果第三个模板参数是 factory_passes_alloc_to_smart_pointer
,则分配器本身将用于 Pointer
的第三个构造函数参数(boost::shared_ptr
然后使用分配器来管理其单独分配的引用计数器的内存)。
#include <boost/functional/factory.hpp>
namespace boost { enum factory_alloc_propagation { factory_alloc_for_pointee_and_deleter, factory_passes_alloc_to_smart_pointer }; template<class Pointer, class Allocator = void, factory_alloc_propagation Policy = factory_alloc_for_pointee_and_deleter> class factory; } // boost
符号
T
至少有一个公共构造函数的任意类型
P
指向 T
的指针或智能指针
a0
...aN
T
的构造函数的实参值
F
类型 factory<P>
f
F
的实例对象
表达式 |
语义 |
---|---|
|
创建类型为 |
|
创建类型为 |
|
使用 |
|
是删除顶层 cv 限定符后的类型 |
在 C++11 之前,支持的参数最大数量为 10。从 C++11 开始,支持任意数量的参数。
Glen Fernandes 重写了 factory
和 value_factory
的实现,以提供以下功能
BOOST_NO_EXCEPTIONS
)以下功能已被删除
BOOST_FUNCTIONAL_VALUE_FACTORY_MAX_ARITY
增加 C++03 编译器的限制boost::none_t
代替 void
为了移除对 Boost.Optional 的依赖,分配器的默认参数已从 boost::none_t
更改为 void
。如果您有代码因为使用 boost::none_t
而停止工作,一个快速修复方法是定义 BOOST_FUNCTIONAL_FACTORY_SUPPORT_NONE_T
,这将恢复支持,但这将在未来的版本中被移除。正确修复这个问题应该相对容易。
感谢 Tobias Schwinger 创建了这个库。
Eric Niebler 请求一个函数来调用类型的构造函数(参数作为元组提供)作为 Fusion 的一个特性。这些工厂工具是这个想法的一个分解概括。
Dave Abrahams 建议使用智能指针来支持异常安全,为实现提供了有用的提示。
Joel de Guzman 的文档风格是从 Fusion 复制的。
感谢 Peter Dimov 分享他对语言细节及其演变的见解。