type адвайсы

Vladimir Migashko edited this page Dec 26, 2013 · 6 revisions

Главная, Основные концепции, АОП, Адвайсы

Этот тип адвайсов удобен для вынесения в аспект класса отдельных определений типов аспектного класса. Type-адвайс представляет собой помеченный тегом некоторый класс, с помощью конструкции fas::type:

typedef fas::type<_counter_, int> counter_advice;

Если необходимо описать несколько зависимых или логически связанных типов, то делается это промежуточную структуру. Например для класса:

class foo
{
public:
  typedef int foo1_type;
  typedef short foo2_type;
  typedef long foo3_type;
};

Определения типов можно вынести в аспект отдельными адвайсами:

struct _foo1_;
struct _foo2_;
struct _foo3_;

struct foo_aspect: fas::aspect< fas::type_list_n<
  fas::type<_foo1_, int>,
  fas::type<_foo2_, short>,
  fas::type<_foo3_, long>
>::type > {};

template<typename A = fas::aspect<> >
class foo
  : public fas::aspect_class< typename fas::merge_aspect<A, foo_aspect>::type >
{
  typedef fas::aspect_class< typename fas::merge_aspect<A, foo_aspect>::type > super;
  typedef typename super::aspect aspect;
public:
  typedef typename fas::advice_cast<_foo1_, aspect >::type foo1_type;
  typedef typename fas::advice_cast<_foo2_, aspect >::type foo2_type;
  typedef typename fas::advice_cast<_foo3_, aspect >::type foo3_type;
};

Либо объединить описание типов в одном месте:

struct _foo_types_;
struct ad_foo_types
{
  typedef int foo1_type;
  typedef short foo2_type;
  typedef long foo3_type;
};
struct foo3_aspect: fas::aspect< fas::type_list_n<
  fas::type<_foo_types_, ad_foo_types>
>::type > {};

template<typename A = fas::aspect<> >
class foo3
  : public fas::aspect_class< typename fas::merge_aspect<A, foo3_aspect>::type >
{
  typedef fas::aspect_class< typename fas::merge_aspect<A, foo3_aspect>::type > super;
  typedef typename super::aspect::template advice_cast<_foo_types_>::type foo_types;
public:
  typedef typename foo_types::foo1_type foo1_type;
  typedef typename foo_types::foo2_type foo2_type;
  typedef typename foo_types::foo3_type foo3_type;
};

Ниже представлен вариант класса счетчика с использованием type-адвайса для определения типа счетчика (еще варианты здесь и здесь):

#include <fas/aop.hpp>
#include <iostream>

struct _counter_;
struct _show_;

struct ad_show
{
  template<typename T>
  void operator()(T& t) const
  {
    int counter = t.get();
    std::cout << "counter: " << counter << std::endl;
  }
};

struct counter_aspect: fas::aspect< fas::type_list_n<
  fas::type<_counter_, int>,
  fas::advice<_show_, ad_show>
>::type > {};

template<typename A = fas::aspect<> >
class counter
  : public fas::aspect_class< typename fas::merge_aspect<A, counter_aspect>::type >
{
  typedef fas::aspect_class< typename fas::merge_aspect<A, counter_aspect>::type > super;
public:
  typedef typename super::aspect::template advice_cast<_counter_>::type counter_type;
  
  counter(): _counter(0) {}
  
  void inc() { ++_counter; }
  void dec() { --_counter; }
  int get() const { return _counter; }
  
  void show() const { this->get_aspect().template get<_show_>()(*this); }
  
private:
  counter_type _counter;
};

int main()
{
  counter<> c;
  c.inc(); c.inc(); c.inc();  
  c.dec();
  c.show();
}

В следующем примере показано, как можно вынести в аспект шаблонные классы, и параметры, с которыми они будут инстанцированы:

#include <fas/aop.hpp>
#include <string>
#include <map>
#include <algorithm>
#include <iostream>

struct _key_;
struct _value_;
struct _comporator_;
struct _allocator_;
struct _container_;
struct _show_;

template< template<typename, typename, typename, typename> class Map = std::map >
struct ad_container
{
  template<typename T>
  struct bind
  {
    typedef typename T::aspect::template advice_cast<_key_>::type key_type;
    typedef typename T::aspect::template advice_cast<_value_>::type mapped_type;
    
    typedef typename T::aspect::template advice_cast<_comporator_>::type comparator_binder;
    typedef typename T::aspect::template advice_cast<_allocator_>::type allocator_binder;
    
    typedef typename comparator_binder::template bind<T>::type comparator_type;
    typedef typename allocator_binder::template bind<T>::type allocator_type;
    
    typedef Map<key_type, mapped_type, comparator_type, allocator_type> type;
  };
};

template< template<typename> class C>
struct ad_compare
{
  template<typename T>
  struct bind
  {
    typedef typename T::aspect::template advice_cast<_key_>::type key_type;
    typedef C<key_type> type;
  };
};

template< template<typename> class A>
struct ad_allocator
{
  template<typename T>
  struct bind
  {
    typedef typename T::aspect::template advice_cast<_key_>::type key_type;
    typedef typename T::aspect::template advice_cast<_value_>::type mapped_type;
    typedef A< std::pair< const key_type, mapped_type> > type;
  };
};

struct ad_show
{
  struct f_show
  {
    template<typename V>
    void operator()( const V& value) const
    {
      std::cout << value.first << ":" << value.second << std::endl;
    }
  };
  
  template<typename T>
  void operator()(T& t) const
  {
    std::for_each(t.begin(), t.end(), f_show() );
  };
};

struct dictonary_aspect: fas::aspect< fas::type_list_n<
  fas::type<_key_, std::string >,
  fas::type<_value_, std::string >,
  fas::type<_comporator_, ad_compare<std::less> >,
  fas::type<_allocator_, ad_allocator<std::allocator> >,
  fas::type<_container_, ad_container<std::map> >,
  fas::advice<_show_, ad_show >
>::type > {};

struct show_aspect: fas::aspect< fas::type_list_n<
  fas::advice<_show_, ad_show >
>::type > {};

template<typename A>
struct dictonary_binder
{
  typedef fas::aspect_class< typename fas::merge_aspect<A, dictonary_aspect>::type > class_type;
  typedef typename class_type::aspect::template advice_cast<_container_>::type container_binder;
  // std::map<std::string, std::string>
  typedef typename container_binder::template bind<class_type>::type type;
};

template<typename A = fas::aspect<> >
class dictonary
  : public dictonary_binder<A>::type // std::map<std::string, std::string>
  , public fas::aspect_class< typename fas::merge_aspect<A, dictonary_aspect>::type >
{
public:
  void show() const
  {
    this->get_aspect().template get<_show_>()(*this);
  }
};

struct greater: fas::aspect< fas::type_list_n<
  fas::type<_comporator_, ad_compare<std::greater> >
>::type > {};

int main()
{
  dictonary<> d;
  d["a"]="a";
  d["b"]="b";
  d.show();
  std::cout << "---" << std::endl;
  dictonary<greater> d2;
  d2["a"]="a";
  d2["b"]="b";
  d2.show();
}

Результат выполнения программы:

a:a
b:b
---
b:b
a:a