……这是世界上备受推崇且设计精良的 C++ 库项目之一。
— Herb Sutter 和 Andrei Alexandrescu, 《C++ Coding Standards》
模板 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 或更高版本中,参数可以是左值或右值。
在传统的面向对象编程中,工厂(Factory)是一个实现了一个或多个方法接口的对象,这些方法用于构造符合已知接口的对象。
// 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_FUNCTIONAL_FACTORY_SUPPORT_NONE_T
使用 boost::none_t
替代 void
为了移除对 Boost.Optional 的依赖,分配器的默认参数已从 boost::none_t
更改为 void
。如果您有代码因使用 boost::none_t
而停止工作,一个快速修复方法是定义 BOOST_FUNCTIONAL_FACTORY_SUPPORT_NONE_T
,这将恢复支持,但这将在未来版本中移除。相对容易可以正确修复。
Tobias Schwinger 创建了这个库。
Eric Niebler 请求一个函数,用于(将参数作为 Tuple 提供)调用类型构造函数,作为 Fusion 的一项功能。这些 Factory 工具是这个想法的一个分解的泛化。
Dave Abrahams 提出了对智能指针异常安全的支持,并提供了有用的实现提示。
Joel de Guzman 的文档风格模仿了 Fusion。
Peter Dimov 分享了他对语言细节及其演变的见解。