Boost C++ 库

……这是世界上备受推崇且设计精良的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, 《C++ Coding Standards》

第 1 章。Boost.Functional/Factory 1.0 - Boost C++ 函数库

第 1 章。Boost.Functional/Factory 1.0

Tobias Schwinger

Glen Fernandes

根据 Boost 软件许可证,版本 1.0 分发。

模板 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_adapterboost::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_factoryboost::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_factoryboost::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 的实例对象

表达式语义

表达式

语义

F()

创建类型为 F 的对象。

F(f)

创建类型为 F 的对象。

f(a0...aN)

返回 T(a0...aN)

F::result_type

是类型 T

限制

在 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 的实例对象

表达式语义

表达式

语义

F()

创建类型为 F 的对象。

F(f)

创建类型为 F 的对象。

f(a0...aN)

使用 a0...aN 作为构造函数调用的参数,动态创建类型为 T 的对象。

F::result_type

是去掉顶层 cv 限定符后的类型 P

限制

在 C++11 之前,支持的最大参数数量为 10。自 C++11 起,支持任意数量的参数。

Boost 1.72.0

Glen Fernandes 重写了 factoryvalue_factory 的实现,以提供以下功能:

  • 在可用时支持右值参数
  • 在可用时通过可变参数模板支持任意数量的参数
  • 支持最终分配器
  • 支持使用高级指针的分配器
  • 支持禁用异常 (BOOST_NO_EXCEPTIONS)
  • 改善了编译时间

已删除以下功能:

  • 通过 BOOST_FUNCTIONAL_VALUE_FACTORY_MAX_ARITY 增加 C++03 编译器的限制
  • 通过 BOOST_FUNCTIONAL_FACTORY_SUPPORT_NONE_T 使用 boost::none_t 替代 void

Boost 1.58.0

为了移除对 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 分享了他对语言细节及其演变的见解。

  1. 《设计模式》,Gamma 等人 - Addison Wesley 出版社,1995 年
  2. 《Standard Template Library Programmer's Guide》,惠普公司,1994 年
  3. Boost.Bind,Peter Dimov,2001-2005 年
  4. Boost.Function,Douglas Gregor,2001-2004 年