/Loki11

loki lib update to c++11

Primary LanguageC++The UnlicenseUnlicense

Loki11 lib

update andrei's loki lib to C++11 主要改进

  • 接口改为使用variadic templates,不再是typelist,实现中用到typelist的地方改为使用boost mp11库的mp_list
  • typelist算法改为使用mp11的算法。
  • 将typetraits部分改为直接使用C++11的type_traits
  • 将functor删除,改为使用C++11的std::function

简要对比loki11和loki 以factory为例说明,Loki11工厂创建抽象对象只有一个成员模板

template<class ID, class... Arg>
AbstractProduct *CreateObject(const ID &id, Arg &&...arg)

而loki的factory有许多成员

AbstractProduct* CreateObject(const IdentifierType& id)
AbstractProduct* CreateObject(const IdentifierType& id, Parm1 p1)
AbstractProduct* CreateObject(const IdentifierType& id, Parm1 p1, Parm2 p2)
...

分别用于表示创建方法不带参数,带一个参数,带两个参数等等。可以看到借助于variadic template我们用一个模板替换了以前的n个成员函数。

Factory使用方法

Factory模板位于loki/Factory.h 声明

template<
  typename IdentifierType,
  template<typename, class>
  class FactoryErrorPolicy,
  class AbstractProduct,
  class... Param>
class Factory ;

如果你想为某一继承体系提供object factories,上述声明中的AbstractProduct 应指定为该继承体系的base class.

IdentifierType 用来标识继承体系中的某个型别。IdentifierType必须是有序型别(ordered Type),能作为std::map的key类型,常用的类型如int, std::string等

FactoryErrorPolicy用于指定错误处理的策略。

Factory实作出以下基本操作

bool Register(const IdentifierType &id, const std::function<AbstractProduct *(Param...)>& creator)

creator 是用来创建对象的functor, 能接受参数Param...,返回类型为AbstractProduct指针。

  template<class ID, class... Arg>
  AbstractProduct *CreateObject(const ID &id, Arg &&...arg);

以上函数查询id是否注册过,如果注册过的话,调用id对应的creator方法,参数为arg...来创建对象,返回结果。 例子:

#include <iostream>
#include <string>
#include <loki/Factory.h>


using namespace Loki;
using std::cout;
using std::endl;


////////////////////////////////////////////
// Object to create: Product
// Constructor with 0 and 2 arguments
////////////////////////////////////////////

class AbstractProduct
{
public:
  virtual int get_x() const = 0;
  virtual int get_y() const = 0;
  virtual ~AbstractProduct() = default;
};

class Product : public AbstractProduct
{
  int x = 0;
  int y = 0;

public:
  Product() = default;
  Product(int xa, int ya) : x(xa), y(ya) {}
  int get_x() const
  {
    return x;
  }
  int get_y() const
  {
    return y;
  }
};

///////////////////////////////////////////////////////////
// Factory for creation a Product object without parameters
///////////////////////////////////////////////////////////

typedef Factory<int, DefaultFactoryError, AbstractProduct>
  PFactoryNull;

/////////////////////////////////////////////////////////////
// Factory for creation a Product object with 2 parameters
/////////////////////////////////////////////////////////////

typedef Factory<int, DefaultFactoryError, AbstractProduct, int, int>
  PFactory;

////////////////////////////////////////////////////
// Creator functions with different names
////////////////////////////////////////////////////

Product *createProductNull()
{
  cout << "createProductNull()" << endl;
  return new Product;
}
Product *createProductParm(int a, int b)
{
  cout << "createProductParm( int a, int b ) " << endl;
  return new Product(a, b);
}



void testFactoryNull()
{
  PFactoryNull pFactoryNull;
  bool const ok1 = pFactoryNull.Register(1, createProductNull);
  if (ok1) {
    std::unique_ptr<AbstractProduct> pObject(pFactoryNull.CreateObject(1));
    if (pObject.get()) {
      cout << "pObject->get_x() = " << pObject->get_x() << endl;
      cout << "pObject->get_y() = " << pObject->get_y() << endl;
    }
  }
}

void testFactoryBinary()
{
  PFactory pFactoryNull;
  bool const ok1 = pFactoryNull.Register(1, createProductParm);
  if (ok1) {
    std::unique_ptr<AbstractProduct> pObject(pFactoryNull.CreateObject(1, 5, 5));
    if (pObject) {
      cout << "pObject->get_x() = " << pObject->get_x() << endl;
      cout << "pObject->get_y() = " << pObject->get_y() << endl;
    }
  }
}

int main()
{
  testFactoryNull();
  testFactoryBinary();
}

输出:

  createProductNull()
  pObject->get_x() = 0
  pObject->get_y() = 0
  createProductParm( int a, int b ) 
  pObject->get_x() = 5
  pObject->get_y() = 5

visitor

visitor模式是一种设计模式,它可以在不改变数据结构的情况下,为数据结构中的元素添加新的操作。visitor模式的目的是将数据结构与数据操作分离。visitor模式的优点是增加新的操作很容易,因为增加新的操作就意味着增加一个新的visitor。

若要实作Acyclic Visitor,请使用 Basevisitor作为"strawman" base class及 visitor和visitable:

class BaseVisitor;

template<typename R, bool constparam, class... Head>
class Visitor;

template<
  typename R = void,
  bool ConstVisitable = false,
  template<typename, class> class CatchAll = DefaultCatchAll>
class BaseVisitable;

Visitor和BaseVisitable的第一个template参数分别是成员函数Visit()的返回值类型和BaseVisitable的返回值类型。第二个参数指定Visit()的参数是否为const引用。 BaseVisitable的第三个template参数是个policy,用来处理catch-all问题

从BaseVisitable派生出你的继承体系的root class,然后在这个继承体系的每一个class中使用宏DEFINE_VISITABLE()。

从Visitor<R,ConstVisitable ,Product... >中派生出你的concrete visitor classes,这里的Product是你的产品继承体系里的所有的类型,并针对继承体系中的每一个类实作出成员函数 Visit:

class VariableVisitor : public Loki::Visitor < void
  , false,Shape, Circle > {
 public:
  void Visit(Shape&) { std::cout << "void Visit(Shape&)\n"; }
  void Visit(Circle&) { std::cout << "void Visit(Circle&)\n"; }
};

例子:

#include <loki/Visitor.h>
#include <iostream>

class Shape : public Loki::BaseVisitable<>
{
 public:
  LOKI_DEFINE_VISITABLE()
};

class Circle : public Shape
{
 public:
  LOKI_DEFINE_VISITABLE()
};

class VariableVisitor : public Loki::Visitor < void
  , false,Shape, Circle > {
 public:
  void Visit(Shape&) { std::cout << "void Visit(Shape&)\n"; }
  void Visit(Circle&) { std::cout << "void Visit(Circle&)\n"; }
};

class CShape : public Loki::BaseVisitable<void,true>
{
 public:
  LOKI_DEFINE_CONST_VISITABLE()
};

class CCircle : public CShape
{
 public:
  LOKI_DEFINE_CONST_VISITABLE()
};

class CVariableVisitor : public Loki::Visitor<void,true, CShape,CCircle>
{
 public:
  void Visit(const CShape&) { std::cout << "void Visit(CShape&)\n"; }
  void Visit(const CCircle&) { std::cout << "void Visit(CCircle&)\n"; }
};

int main()
{
  VariableVisitor visitor;
  Circle           circle;
  Shape*           dyn = &circle;
  Shape           shape ;
  dyn->Accept(visitor);
  dyn = &shape;
  dyn->Accept(visitor);

  CVariableVisitor cvisitor;
  CCircle           ccircle;
  CShape*           cdyn = &ccircle;
  cdyn->Accept(cvisitor);
  CShape cshape;
  cdyn = &cshape;
  cdyn->Accept(cvisitor);
}

AbstractFactory 和ConcreteFactory用法概览

template<class... U>
using AbstractFactory = ...;

其中U...参数包,用来指定这个Factory将要生成的abstract products。例如

using AbstractEnemyFactory=AbstractFactory<Soldier, Monster>;

AbstractFactory提供一个名为Create()的成员函数,可以用abstract products中的一个类型来实例化,用于创建一个abstract product。例如

AbstractEnemyFactory factory;
auto soldier = factory.Create<Soldier>();
auto monster = factory.Create<Monster>();

为实现AbstractFactory所定义的接口,Loki提供了一个concreteFactory template,大致如下:

template<class AbstractFact, 
class TList = typename AbstractFact::ProductList>
  using ConcreteFactory = ...;

其中AbstractFact是将被实作出来之AbstractFactory模板的实例,如上文的AbstractEnemyFactory,TList是concrete products typelist,如mp::mp_list<SillySoldier,SillyMonster>。

例子:

#include <iostream>
#include <string>
#include <memory>
#include <loki/AbstractFactory.h>


using namespace Loki;
using std::cout;
using std::endl;

struct Soldier
{
public:
  virtual ~Soldier(){};

  virtual void print() const {
  
    cout << "Soldier\n";
  }
};

struct SillySoldier:public Soldier
{
public:
  virtual void print() const {
    cout << "SillySoldier\n";
  }
};

struct Monster
{
public:
  virtual ~Monster() =default;
  virtual void print() const = 0;
};

struct SillyMonster:public Monster
{
public:
  virtual void print() const {
    cout << "SillyMonster\n";
  }
};
using AbstractEnemyFactory=AbstractFactory<Soldier, Monster>;

using ConcreteEnemyFactory= ConcreteFactory<AbstractEnemyFactory, mp::mp_list<SillySoldier,SillyMonster>> ;
int main() {
  ConcreteEnemyFactory cef;
  AbstractEnemyFactory *pA = &cef;
  auto pS = pA->Create<Soldier>();
  std::unique_ptr<Soldier> p(pS);
  p->print();
}