博客 阅读时间 3 分钟

现代 C++ 设计:跟随 Loki 库学习

分享本文
Modern C++ Design: Learn with the Loki Library

如果您决定开始学习现代 C++ 设计,而且出身于面向对象编程(OOP)学派,那么可以从研究Loki库开始。

Loki是一个 C++ 软件库的名字,由 Andrei Alexandrescu 编写,是其著作《Modern C++ Design》(现代 C++ 设计)的一部分。

该库大量使用 C++ 模板元编程,并实现了多个常用工具:类型列表(typelist)、仿函数(functor)、单例(singleton)、智能指针、对象工厂、访问者(visitor)和多方法(multimethod)。

下面是作者设计这个库背后的动机:

  • Loki 用户只需为自己想要的特性付出代价。Loki 的每个组件都可以独立于其他组件使用。
  • “小即是美”——Loki 的内部依赖很少。
  • “乘法效应最精彩。”——Loki 的特别关注点在于:通过组合小而抽象的行为单元(策略),获得乘法式的行为(即细粒度、专门化的设计)。
  • Loki 专注于战略而非战术;专注于设计而非细枝末节;专注于架构组件而非大杂烩。
  • 由于 Loki 是一个“设计的集合”,而不是“一个库的设计”,它应当对自身环境做最少的假设,并在选择了某个默认决策之处提供恰当的挂钩(hook)。
  • Loki 不会迁就能力较弱的编译器。Loki 的目标是在标准 C++ 的范畴内编写可读的代码。
  • 这些组件理想情况下应当小巧、易于理解和正确使用,无论单独使用还是组合使用都很实用,并能在项目中发挥巨大作用。

但在深入研究它的现代 C++ 惯用法之前,最好先掌握模板编程中的一个核心概念:基于策略的设计(policy-based design)惯用法。

基于策略设计的核心惯用法是一个类模板(称为宿主类),它接受若干类型参数,这些参数由用户选定的类型(称为策略类)实例化,每个策略类各自实现一个特定的隐式接口(称为策略),并封装宿主类实例化后行为中某个正交(或基本正交)的方面。通过提供一个宿主类,并配套每种策略的一组不同的现成实现,一个库或模块就能支持指数级数量的不同行为组合——这些组合在编译期解析,通过在宿主类模板实例化时混搭不同的策略类来选择。

下面是一个来自维基百科的小例子,演示了这个实用的惯用法:

#include 
#include 
 
template 
class HelloWorld : private OutputPolicy, private LanguagePolicy
{
    using OutputPolicy::print;
    using LanguagePolicy::message;
 
public:
    // Behaviour method
    void run() const
    {
        // Two policy methods
        print(message());
    }
};
 
class OutputPolicyWriteToCout
{
protected:
    template
    void print(MessageType const &message) const
    {
        std::cout << message << std::endl;
    }
};
 
class LanguagePolicyEnglish
{
protected:
    std::string message() const
    {
        return "Hello, World!";
    }
};
 
class LanguagePolicyGerman
{
protected:
    std::string message() const
    {
        return "Hallo Welt!";
    }
};
 
int main()
{
    /* Example 1 */
    typedef HelloWorld<OutputPolicyWriteToCout, LanguagePolicyEnglish> HelloWorldEnglish;
 
    HelloWorldEnglish hello_world;
    hello_world.run(); // prints "Hello, World!"
 
    /* Example 2 
     * Does the same, but uses another language policy */
    typedef HelloWorld<OutputPolicyWriteToCout, LanguagePolicyGerman> HelloWorldGerman;
 
    HelloWorldGerman hello_world2;
    hello_world2.run(); // prints "Hallo Welt!"
}

了解基于策略的设计之后,您可以继续学习该库使用的其他惯用法:

  • 多重分发器(Multiple dispatcher)
  • Pimpl(指针实现惯用法)
  • Printf(一种类型安全的 printf 替代方案)
  • 有序静态对象创建
  • 作用域守卫指针(Scope guard pointer)
  • 小对象分配器(Small Object Allocator)
  • 智能指针
  • 编译期检查

您可以在这个有趣的资源中找到对上述惯用法的详细讲解。

总而言之,Loki 库虽不如 STL 或 Boost 那样流行,但它是一个很有趣的教学型库,可用于学习现代 C++ 设计的基本惯用法。它是掌握现代 C++ 设计的良好起点。

分享本文