I have a complex code base at work, and i created a small example to mimic the problem and here is the below code.
< Code below for reference> - This code is compilable if we have boost libraries and FastDelegate.h linked with the project. Please let me know if you need the full compilable example project, i can email you.
I have two problems and need help resolving them.
As seen below in the code, i have a class with argument type as template for another classes object. Now when i initialize the class below in UserClass's constructor (Line 107) i get error because mBaseAcceptor is a class with template argument of type base Class, but i need to do mbaseAcceptor(new derivedAcceptor_t). Casting problem how to fix this?
Error here is
./boost/smart_ptr/shared_ptr.hpp:387:9: error: comparison between distinct pointer types ‘Acceptor<DerivedClass>*’ and ‘Acceptor<BaseClass>*’ lacks a cast
Another problem is in line 108, even if i magically say resolve this by using another acceptor of derived class, this is where i use that mDerivedAcceptor, in Line 108 i do
mDerivedAcceptor->SetDelegate(fastdelegate::MakeDelegate(this, &UserClass::HandleDelegate));
then i get error saying
"error no matching function call for HandleDelegate(DerivedClass&, bool).
This make sense because HandleDelegate has argument of type BaseClass and by storing a delegate(which is a func. ptr) we have to call the function with appropriate argument. But how to fix this.
If i cast Handler inside Acceptor class with derived class will it work when i only pass the baseClass pointer?
Code
/*
* smart_pointer_1.cpp
*
* Created on: Jul 26, 2011
* Author: balaji
*/
#include <algorithm>
#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include "FastDelegate.h"
#include <iostream>
using namespace std;
template <class Handler>
class Acceptor {
public:
typedef fastdelegate::FastDelegate1<Handler &, bool> delegate_t;
Acceptor ();
void Initialize(Handler *&handle);
void SetDelegate(delegate_t delegate) { mDelegate = delegate; }
private:
int mValues[2];
delegate_t mDelegate;
};
template <class Handler>
Acceptor<Handler>::Acceptor()
{
std::cout << "In Constructor: " << __FUNCTION__ << std::endl;
mValues[0] = 1;
mValues[1] = 2;
}
template <class Handler>
void Acceptor<Handler>::Initialize(Handler *&handle){
if (!handle) {
std::cout << __FUNCTION__ << " : created" << std::endl;
handle = new Handler();
} else {
std::cout << __FUNCTION__ << " : Error exception" << std::endl;
}
if (mDelegate && mDelegate(*handle)) {
std::cout << "Ok Called Handle in " << __FUNCTION__ << std::endl;
} else {
std::cout << "Not Called Handle in " << __FUNCTION__ << std::endl;
}
handle->displayComputer();
}
class BaseClass {
std::string mComputer;
public:
BaseClass() {
std::cout << "In Base Constructor: " << __FUNCTION__ << std::endl;
mComputer = "Mac";
}
virtual void displayComputer() {
std::cout << "Computer type is " << mComputer << std::endl;
}
};
class DerivedClass : public BaseClass {
std::string mLanguage;
public:
DerivedClass() {
std::cout << "In Derived Constructor: " << __FUNCTION__ << std::endl;
mLanguage = "C++";
}
void displayComputer() {
std::cout << "Language is " << mLanguage << std::endl;
}
};
class UserClass {
public:
UserClass();
UserClass(bool);
typedef Acceptor<BaseClass> baseAcceptor_t;
typedef Acceptor<DerivedClass> derivedAcceptor_t;
typedef boost::shared_ptr<BaseClass> basePtr_t;
void CallDelegate(BaseClass&);
private:
boost::shared_ptr<baseAcceptor_t> mBaseAcceptor;
boost::shared_ptr<derivedAcceptor_t> mDerivedAcceptor;
BaseClass *mConnBasePtr;
bool HandleDelegate(BaseClass& baseDelegate);
};
UserClass::UserClass() : mBaseAcceptor(new baseAcceptor_t)
{
std::cout << "In Constructor: " << __FUNCTION__ << std::endl;
mBaseAcceptor->SetDelegate(fastdelegate::MakeDelegate(this, &UserClass::HandleDelegate));
mBaseAcceptor->Initialize(mConnBasePtr);
}
UserClass::UserClass(bool value)
{
std::cout << "In Constructor: " << __FUNCTION__ << std::endl;
mBaseAcceptor.reset(new derivedAcceptor_t); // <<========== Problem Here because of improper casting
mBaseAcceptor->SetDelegate(fastdelegate::MakeDelegate(this, &UserClass::HandleDelegate)); // <<=== Also here because of improper type passed to MakeDelegate function ptr. Please note HandleDelegate has an argument of type BaseClass, but Acceptor is derived class
mBaseAcceptor->Initialize(mConnBasePtr);
}
bool UserClass::HandleDelegate(BaseClass& baseDelegate)
{
std::cout << "In " << __FUNCTION__ << std::endl;
return true;
}
int main() {
std::cout << "In function: " << __FUNCTION__ << std::endl;
typedef boost::shared_ptr<UserClass> userPtr_t;
userPtr_t user(new UserClass(true));
std::cout << "In function: " << __FUNCTION__ << " at end "<< std::endl;
return 0;
}
Acceptor<DerivedClass> is not derived from Acceptor<BaseClass> (it doesn't matter that DerivedClass is derived from BaseClass or not) so the compiler can not cast one into the other.
I would get rid of the templatization of the acceptor, unless you have a good reason to keep it (which I don't see in your code) :
class Acceptor {
public:
typedef fastdelegate::FastDelegate1<BaseClass &, bool> delegate_t;
Acceptor ();
void Initialize(BaseClass *handle);
void SetDelegate(delegate_t delegate) { mDelegate = delegate; }
private:
int mValues[2];
delegate_t mDelegate;
};
void Acceptor::Initialize(BaseClass *handle){
if (!handle) {
std::cout << __FUNCTION__ << " : Error exception" << std::endl;
}
if (mDelegate && mDelegate(*handle)) {
std::cout << "Ok Called Handle in " << __FUNCTION__ << std::endl;
} else {
std::cout << "Not Called Handle in " << __FUNCTION__ << std::endl;
}
handle->displayComputer();
}
Then you don't need separate baseAcceptor_t and derivedAcceptor_t types as they both become simply Acceptor, and you can do for example :
UserClass::UserClass() : mBaseAcceptor(new Acceptor(new BaseClass))
As far as I see the only thing you loose is the ability to pass a null pointer to the acceptor's constructor and have it create its handler itself. That's a very minor loss as the real decision (instantiate a base or a derived handler) is really taken when you instantiate the Acceptor anyway (because you choose which of Acceptor<BaseClass> or Acceptor<DerivedClass> you want)
Define base class for the Acceptor template and another class that will be base to all Handler types. So your implementation will change to:
class IHandler {
};
class IAcceptor {
public:
virtual void Initialize(IHandler *) = 0;
virtual void SetDelegate(delegate_t delegate) = 0;
};
Your Acceptor template will change to:
template <class Handler>
class Acceptor : public IAcceptor {
public:
typedef fastdelegate::FastDelegate1<Handler &, bool> delegate_t;
Acceptor ();
void Initialize(IHandler *pVal);
void SetDelegate(delegate_t delegate) { mDelegate = delegate; }
private:
int mValues[2];
delegate_t mDelegate;
};
Your implementation for Initialize will change (Make sure you handle the dynamic_cast result correctly):
template <class Handler>
void Acceptor<Handler>::Initialize(IHandler *pVal){
Handler *pHandle = dynamic_cast<Handler>(pVal); //You will have to ofcourse ttake appropriate action if this cast fails.
if (!handle) {
std::cout << __FUNCTION__ << " : created" << std::endl;
handle = new Handler();
} else {
std::cout << __FUNCTION__ << " : Error exception" << std::endl;
}
if (mDelegate && mDelegate(*handle)) {
std::cout << "Ok Called Handle in " << __FUNCTION__ << std::endl;
} else {
std::cout << "Not Called Handle in " << __FUNCTION__ << std::endl;
}
handle->displayComputer();
}
Finally all classes that have to be used with the Acceptor will have to be derived from IHandler.
Now you can change your pointer declaration to shared_ptr< IAcceptor >.
EDIT:
Based on your comment for the second issue, I would pass the Handler object as a pointer instead of a reference and modify the UserClass::HandleDelegate method to accept a pointer to the BaseClass (or the IHandler class if you want to be even more generic.).
You can try to use boost::static_pointer_cast, because even though
class Derived : public Base{};
it doesn't make boost::shared<Derived> inherit from boost::shared_ptr<Base>.
So you have to use explicit boost cast like boost::static_pointer_cast, boost::dynamic_pointer_cast accordingly.
Related
Is it possible to specialize a template class by argument instead by type?
The target is to have a comfortable interface and as less as possible execution time.
At the moment I know three options with different benefits.
One Class with different beaviour depending on CTor Parameter
Define different classes
Specialized template classes
The first possibility does not fit the execution time requirement.
The second possibility does not have a nice interface, because everybody has to know that there are multiple classes with just slighly different behaviour.
The third solution is my favorit, but therefore it is needed to declare types as switches.
So I am looking for a mixture between 1. and 3.
I may be missing the correct keywords to search with.
Here the possibilities I know so far:
#include <iostream>
/**
* opt1 -- switch at runtime
*/
class inoutslow
{
public:
inoutslow(bool b): _switch(b)
{
if(_switch)
std::cout << "slowIn1" << std::endl;
else
std::cout << "slowIn2" << std::endl;
}
~inoutslow()
{
if(_switch)
std::cout << "slowOut1" << std::endl;
else
std::cout << "slowOut2" << std::endl;
}
private:
bool _switch;
};
/**
* opt2 -- different self defined classes
*/
class inout1
{
public:
inout1(){std::cout << "in1" << std::endl;}
~inout1(){std::cout << "out1" << std::endl;}
};
class inout2
{
public:
inout2(){std::cout << "in2" << std::endl;}
~inout2(){std::cout << "out2" << std::endl;}
};
/**
* opt3 -- specialized template
*/
struct trueType;
struct falseType;
template<typename T>
class inout
{
public:
inout(){std::cout << "DefaultTin" << std::endl;}
~inout(){std::cout << "DefaultTout" << std::endl;}
};
template <>
class inout<trueType>
{
public:
inout(){std::cout << "Tin1" << std::endl;}
~inout(){std::cout << "Tout1" << std::endl;}
};
template <>
class inout<falseType>
{
public:
inout(){std::cout << "Tin2" << std::endl;}
~inout(){std::cout << "Tout2" << std::endl;}
};
int main()
{
inoutslow i(true);
inoutslow j(false);
inout1 ii;
inout2 jj;
inout<trueType> iii;
inout<falseType> jjj;
}
the above code in coliru
Thank you guys -- for all those who might find this question instead of Using template instead of switch
/**
* opt 4
*/
template<bool _switch>
class inoutT;
template <>
class inoutT<true>
{
public:
inoutT(){std::cout << "TTin1" << std::endl;}
~inoutT(){std::cout << "TTout1" << std::endl;}
};
template <>
class inoutT<false>
{
public:
inoutT(){std::cout << "TTin2" << std::endl;}
~inoutT(){std::cout << "TTout2" << std::endl;}
};
working sample of all (listed) possibilities
I'm trying to pass a method as a parameter to other method.
Magner.h:
Class Manager{
public:
timeCount(void (Manger::*function)(void));
void passedFuction();
}
In Manager.cpp, I'm trying to call timeCount by
timeCount(&Manager::passedFuction());
TimeCount Body:
void Manager::timeCount(void(Manager::*function)(void))
{
std::cout << "It works";
(*function)(); // here is error
}
ViusalStudio says:
void*Manager::*function)() operand of '*' must be a pointer
How should i correct it?
The example i was learing by was : http://www.cplusplus.com/forum/beginner/6596/
A pointer-to-member-function (pmf) is not a pointer. Let me repeat that:
A pointer-to-member-function is not a pointer.
To call a pmf, you have to provide it with the object you want to call it on. You probably want:
(this->*function)();
If you had another object obj of the right type, you could also use:
(obj.*function)();
The void (Manger::*function)(void) syntax is for member functions of Manager class, which cannot be used with functions outside the Manager class.
To fix this shortcoming, pass std::function<void(void)> instead, which would let you invoke itself using the regular function invocation syntax:
void Manager::timeCount(std::function<void(void)> f) {
std::cout << "It works";
f();
}
Here is a complete demo of how to call timeCount with member and non-member functions:
struct Manager {
string name;
void timeCount(std::function<void(void)> f) {
std::cout << "This is " << name << " manager" << endl;
f();
}
};
void foo() {
cout << "I'm foo" << endl;
}
struct Test {
int x;
void bar() {
cout << "I'm bar " << x << endl;
}
};
int main() {
Manager mgr {"time"};
mgr.timeCount(foo);
Test tst = {234};
mgr.timeCount(std::bind( &Test::bar, tst));
return 0;
}
Demo.
Since c++17, we have std::invoke:
std::invoke(function, this);
or
std::invoke(function, *this);
are both ok. Minimal demo:
#include <functional>
#include <iostream>
class Manager
{
public:
void timeCount(void (Manager::*function)(void));
void passedFuction()
{
std::cout << "call passedFunction\n";
}
};
void Manager::timeCount(void (Manager::*function)(void))
{
std::cout << "It works\n";
std::invoke(function, *this);
// (*function)(); // here is error
}
int main()
{
Manager a;
a.timeCount(&Manager::passedFuction);
}
It works
call passedFunction
live demo
I would like to have "yet another" callback registration stuff.
Different event types extending a common base event type will trigger associated callback functions.
here is the initial draft or idea
#include <functional>
#include <iostream>
#include <unordered_map>
class BaseEvent
{
public:
virtual ~BaseEvent() {}
};
class DerivedEvent_1 : public BaseEvent {};
class DerivedEvent_2 : public BaseEvent {};
// a container holding callback functions
std::unordered_map<size_t/*event*/, std::function<void(BaseEvent)>/*callback*/> _callbacks;
// register callback funtion associated with specific event
template<typename EVT>
void registerCallback(std::function<void(EVT)> cb)
{
std::cout << "store callback associated with event " << typeid(EVT).name() << " [" << typeid(EVT).hash_code() << "]" << std::endl;
//_functions[ typeid(EVT).hash_code() ] = cb; // FIXME
}
// trigger callback function
void triggerCallback(const BaseEvent* e)
{
std::cout << "trigger callback with event " << typeid(*e).name() << " [" << typeid(*e).hash_code() << "]" << std::endl;
//_functions[ typeid(*e).hash_code() ] (*e); // FIXME
}
// callback function for DerivedEvent_1
void callback_1(DerivedEvent_1 event_1)
{
std::cout << "callback_1 called" << std::endl;
}
// callback function for DerivedEvent_2
void callback_2(DerivedEvent_2 event_2)
{
std::cout << "callback_2 called" << std::endl;
}
int main(int argc, char *argv[])
{
registerCallback<DerivedEvent_1>( [](DerivedEvent_1 e) { callback_1(e); } );
registerCallback<DerivedEvent_2>( [](DerivedEvent_2 e) { callback_2(e); } );
DerivedEvent_1 e1;
DerivedEvent_2 e2;
triggerCallback(&e1);
triggerCallback(&e2);
return 1;
}
so far so good without real implementation...
$ g++ -std=c++11 -o testStdFunction testStdFunvtion.cpp
$ ./testStdFunction
store callback associated with event 14DerivedEvent_1 [4527193776]
store callback associated with event 14DerivedEvent_2 [4527193680]
trigger callback with event 14DerivedEvent_1 [4527193776]
trigger callback with event 14DerivedEvent_2 [4527193680]
The situations and questions are:
Events are class or struct which can have specific attributes as payload
I would like to keep callback functions (e.g. void callback_1(DerivedEvent_1 event_1) without pointer as argument. Reason: those callback functions may already exist in code base and I would like to not change it or make extra wrapper.
how can I let _callbacks map to have std::function with different signatures?
i.e. to let the _callbacks map can hold std::function
The intention is to fix the FIXME code in registerCallback and triggerCallback. so they will look like this after running the code
$ g++ -std=c++11 -o testStdFunction testStdFunvtion.cpp
$ ./testStdFunction
store callback associated with event 14DerivedEvent_1 [4527193776]
store callback associated with event 14DerivedEvent_2 [4527193680]
trigger callback with event 14DerivedEvent_1 [4527193776]
callback_1 called
trigger callback with event 14DerivedEvent_2 [4527193680]
callback_2 called
You can use an erased wrapper.
The following code prints exactly the messages the OP posted in the question.
Key classes are BaseWrapper and the template class Wrapper.
Moreover, I slightly changed function signatures all around the code to let it work correctly.
#include <functional>
#include <iostream>
#include <unordered_map>
#include<memory>
#include<utility>
class BaseEvent
{
public:
virtual ~BaseEvent() {}
};
class DerivedEvent_1 : public BaseEvent {};
class DerivedEvent_2 : public BaseEvent {};
struct BaseWrapper {
virtual void operator()(const BaseEvent *) = 0;
};
template<typename T>
struct Wrapper: BaseWrapper {
std::function<void(T)> fn;
void operator()(const BaseEvent *e) {
fn(*static_cast<const T*>(e));
}
};
// a container holding callback functions
std::unordered_map<size_t/*event*/, std::unique_ptr<BaseWrapper>/*callback*/> _functions;
// register callback funtion associated with specific event
template<typename EVT>
void registerCallback(std::function<void(const EVT &)> cb)
{
std::cout << "store callback associated with event " << typeid(EVT).name() << " [" << typeid(EVT).hash_code() << "]" << std::endl;
auto w = std::make_unique<Wrapper<EVT>>();
w->fn = cb;
_functions[ typeid(EVT).hash_code() ] = std::move(w);
}
// trigger callback function
void triggerCallback(const BaseEvent* e)
{
std::cout << "trigger callback with event " << typeid(*e).name() << " [" << typeid(*e).hash_code() << "]" << std::endl;
(*_functions[ typeid(*e).hash_code() ] )(e);
}
// callback function for DerivedEvent_1
void callback_1(const DerivedEvent_1 &event_1)
{
std::cout << "callback_1 called" << std::endl;
}
// callback function for DerivedEvent_2
void callback_2(const DerivedEvent_2 &event_2)
{
std::cout << "callback_2 called" << std::endl;
}
int main(int argc, char *argv[])
{
registerCallback<DerivedEvent_1>( [](DerivedEvent_1 e) { callback_1(e); } );
registerCallback<DerivedEvent_2>( [](DerivedEvent_2 e) { callback_2(e); } );
DerivedEvent_1 e1;
DerivedEvent_2 e2;
triggerCallback(&e1);
triggerCallback(&e2);
return 1;
}
The wrapper can be improved in terms of performance (as an example, using static member methods instead of polymorphism, left to the reader as an exercise).
The basic idea behind the solution is the so called type-erasure.
Google will help you in finding further details about that.
in my program I have base GeneralHeader, MacHeader that derived from GeneralHeader and NetworkPacket with member Headers that is std list of GeneralHeader:
//Packet.h
enum HeaderType_t {General_Header_type, MAC_Header_type};
class GeneralHeader {
public:
bool Valid;
HeaderType_t HeaderType;
void PrintMe();
};
struct MACHeader: public GeneralHeader {
long unsigned DestAddr:48;
long unsigned SourceAddr:48;
void PrintMe();
};
struct Packet_t {
list<GeneralHeader> Headers;//TODO GeneralHeader
list<GeneralHeader>::iterator it_Header; //TODO GeneralHeader
void PrintMe();
};
While implementing the PrintMe() of Packet_t, that supposed to print all Headers according to HeaderType: if there is a GeneralHeader - it will use GeneralHeader.PrintMe() and if it is MACHeader in the list - it will print MACHeader.PrintMe())
I'm struggling to cast it_Header iterator from base GeneralHeader to derived MACHeader inside Packet_t method PrintMe():
//Packet.cpp
void GeneralHeader::PrintMe() {
std::cout << "Valid " << GeneralHeader::Valid << endl;
std::cout << "Header Type " << GeneralHeader::HeaderType << endl;
};
void HW_MACHeader::PrintMe() {
std::cout << "------------------------ " << endl;
std::cout << "---- MAC HEADER --- " << endl;
std::cout << "------------------------ " << endl;
GeneralHeader::PrintMe();
};
void NetworkPacket_t::PrintMe() {
std::cout << "Valid Packet " << NetworkPacket_t::ValidPacket << endl;
for (it_Header = Headers.begin(); it_Header != Headers.end(); it_Header++) {
switch (it_Header->HeaderType) {
case MAC_Header_type:
static_cast<HW_MACHeader*>(it_Header)->PrintMe();
break;
default:
std::cout << "default" << endl;
};
it_Header++;
};
};
The error: invalid static_cast from type 'std::_List_iterator' to type 'MACHeader*'
Thank you for any help.
The desired/normal polymorphic way would be:
Redefine PrintMe() to a virtual function so that cast is not necessary:
class GeneralHeader {
public:
bool Valid;
HeaderType_t HeaderType;
virtual void PrintMe();
};
class MACHeader: public GeneralHeader {
long unsigned DestAddr:48;
long unsigned SourceAddr:48;
public:
void PrintMe();
};
Also use vector of pointers to GeneralHeader:
list<GeneralHeader*>::iterator it_Header;
Then you can:
(*it_Header)->printMe();
The for loop will be simpler:
for (it_Header = Headers.begin(); it_Header != Headers.end();++it_Header)
(*it_Header)->PrintMe();
I don't know why you need the it_Header to be a member of the class? Can't it just be local to the loop?
You need to dereference it_Header to access the "underlying" object to address the compiler error :
static_cast<HW_MACHeader*>(*it_Header)->PrintMe();
Hoever, that will not solve your problem: you have a list of GeneralHeader; therefore because you want to downcast to an instance of HW_MACHeader, you need to use dynamic_cast; this has to be done either on a reference or a pointer:
dynamic_cast<HW_MACHeader&>(*it_Header).PrintMe();
The line above takes the object "referenced" by it_Header, and tells the compiler to cast it dynamically to a reference of type HW_MACHeader.
Note that dynamic_cast will return a null pointer if it cannot cast down to the type you want.
However, this is not a proper way to do this. You should follow user2672165's advice, and use virtual functions.
I'm currently playing with mixin layers designs, and I'm stuck with an
annoying problem.
Let's consider the following basic mixin layer:
template <typename Next>
struct Layer1 : public Next
{
struct A : public Next::A
{
void f() { g(); }
void g() {}
};
};
Nothing fancy here, just a simple mixin with 2 methods f() and g().
Notice that the g() call from f() is is statically binded to this
specific Layer1::A::g().
Now, what I want is to be able to completely hook the methods of this
mixin to implement, say, a logging layer:
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;
}
};
};
Considering Layer2<Layer1<...>>, the problem here is that any call of
f() and g() from a layer above Layer2 will properly cascade down to
the Layer2::A::g(), and thus display the proper logging messages. But
any call of f() and g() from below Layer2 will not log anything since
the call would have been statically binded to the g() available at the
time the call was made.
This means that calling f() from any layer above Layer2 will obviously
still always call Layer1::A::g() from Layer1::A::f() and not display
the logging messages.
I came up with 2 solutions to this problem:
Virtuality: clearly not acceptable. The whole point of mixin layers
is to avoid virtuality when not necessary.
Adding a template parameter to the layers to provide the previous
layer, something of the kind.
.
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;
Well, it works, but I would like to hide this second template
parameter since it is redundant.
I wondered if any of you ever encountered such problem, and what
solutions did you developped to solve it, since there is a clear lack
of articles on mixin layers.