Mixin слои и статическое связывание - PullRequest
1 голос
/ 17 июня 2011

В настоящее время я играю с миксиновыми слоями, и я застрял с досадная проблема. Давайте рассмотрим следующий основной слой миксинов:

template <typename Next> 
struct Layer1 : public Next 
{ 
 struct A : public Next::A 
 { 
   void f() { g(); } 
   void g() {} 
 }; 
};

Ничего особенного, просто простой миксин с двумя методами f() и g(). Обратите внимание, что вызов g() из f() статически привязан к этому специфический Layer1::A::g(). Теперь, что я хочу, чтобы иметь возможность полностью подключить методы этого mixin для реализации, скажем, слоя логирования:

template <typename Next> 
struct Layer2 : public Next 
{ 
 struct A : public Next::A 
 { 
   void f() 
   { 
     std::cout << "Layer2::A::f() [enter]" << std::endl; 
     Next::A::f(); 
     std::cout << "Layer2::A::f() [leave]" << std::endl; 
   } 
   void g() 
   { 
     std::cout << "Layer2::A::g() [enter]" << std::endl; 
     Next::A::g(); 
     std::cout << "Layer2::A::g() [leave]" << std::endl; 
   } 
 }; 
};

Учитывая Layer2<Layer1<...>>, проблема здесь в том, что любой вызов f() и g() от уровня выше Layer2 будут правильно каскадно опуститься до Layer2::A::g(), и, таким образом, отображать правильные сообщения регистрации. Но любой вызов f() и g() снизу Layer2 не будет ничего регистрировать, поскольку вызов был бы статически привязан к g(), доступному на время звонка было сделано. Это означает, что вызов f() с любого уровня выше Layer2, очевидно, по-прежнему всегда звоните Layer1::A::g() с Layer1::A::f() и не отображайте протоколирование сообщений. Я придумал 2 решения этой проблемы:

  1. Виртуальность: явно не приемлемо. Весь смысл смешанных слоев это избегать виртуальности, когда это не нужно.

  2. Добавление параметра шаблона в слои для предоставления предыдущего слой, что-то в этом роде.

.

template <typename Next, template <typename> class Prev> 
struct Layer2 : public Next 
{ 
 typedef Next next_t; 
 struct A : public Next::A 
 { 
   void f() 
   { 
     std::cout << "Layer2::A::f() [enter]" << std::endl; 
     Next::A::f(); 
     std::cout << "Layer2::A::f() [leave]" << std::endl; 
   } 
   void g() 
   { 
     std::cout << "Layer2::A::g() [enter]" << std::endl; 
     Next::A::g(); 
     std::cout << "Layer2::A::g() [leave]" << std::endl; 
   } 
 }; 
}; 

template <typename Next, template <typename> class Prev> 
struct Layer1 : public Next 
{ 
 typedef Next next_t; 
 struct A : public Next::A 
 { 
   void f() 
   { 
     std::cout << "Layer1::A::f() [enter]" << std::endl; 
     ((typename Prev<Layer1<Next,Prev> >::A*)this)->g(); 
     std::cout << "Layer1::A::f() [leave]" << std::endl; 
   } 
   void g() 
   { 
     std::cout << "Layer1::A::g() [enter]" << std::endl; 
     std::cout << "Layer1::A::g() [leave]" << std::endl; 
   } 
 }; 
}; 

typedef Layer2<Layer1<Layer0,Layer2>,NullType> Application;

Ну, это работает, но я хотел бы скрыть этот второй шаблон параметр, так как он является избыточным. Интересно, сталкивался ли кто-нибудь из вас с такой проблемой, и что Решения, которые вы разработали, чтобы решить это, так как существует явный недостаток статей на миксиновых слоях.

...