Форварды

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

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

Форвард аналогичен обычному алиасу, за исключением того, что действует с места своего внедрения. Иными словами область его применения распространяется только на те адвайсы аспекта, которые расположенны за определением форварда в списке адвайсов аспекта. При внедрении этого типа адвайсов следует учитывать его позицию в списке аспекта. Форвард описывается с помощью конструкции fas::forward:

typedef fas::forward<_foo_, _bar_> foo_advice;

Форварды, например, могут использоваться в тех случаях, когда требуется расширить функционал некоторого адвайса, используя идиомы "до" и "после", без привязки к конкретным типам. В примере ниже, внедряется дополнительный адвайс, который до и после отображения счетчика выводит строки --- и ===:

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

struct _counter_;
struct _show_;

struct ad_counter
{
  ad_counter(): _counter(0) {}
  void inc() { _counter++; }
  void dec() { _counter--; }
  int get() const { return _counter; }
private:
  int _counter;
};

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

struct counter_aspect: fas::aspect< fas::type_list_n<
  fas::advice<_counter_, ad_counter>,
  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 >
{
public:
  void inc() { this->get_aspect().template get<_counter_>().inc(); }
  void dec() { this->get_aspect().template get<_counter_>().dec(); }
  int get() const { return this->get_aspect().template get<_counter_>().get(); }
  void show() const { this->get_aspect().template get<_show_>()(*this); }
};

/// ////////////////////////////////////////

struct _show_orig_;

struct ad_show_ex
{
  template<typename T>
  void operator()(T& t) const
  {
    std::cout << "---" << std::endl;
    t.get_aspect().template get<_show_orig_>()(t);
    std::cout << "===" << std::endl;
  }
};

struct show_ex: fas::aspect< fas::type_list_n<
  fas::advice<_show_, ad_show_ex>,
  fas::forward<_show_orig_, _show_>
>::type > {};

/// ////////////////////////////////////////

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

Результат:

counter: 2
---
counter: 2
===

Если поменять местами fas::advice<_show_, ad_show_ex> и fas::forward<_show_orig_, _show_> то будет получена рекурсия на этапе выполнения, т.к. ad_show_ex будет рекурсивно вызывать сам себя. Такой же эффект будет получен при использовании fas::alias в место fas::forward, независимо от местоположения в списке.