I'm using a boost typelist to implement the policy pattern in the following manner.
using namespace boost::mpl;
template <typename PolicyTypeList = boost::mpl::vector<> >
class Host : public inherit_linearly<PolicyTypeList, inherit<_1, _2> >::type
{
public:
Host() : m_expensiveType(/* ... */) { }
private:
const ExpensiveType m_expensiveType;
};
The Host
class knows how to create an instance of ExpensiveType
, which is a costly operation, and each policy class exposes functionality to use it. A policy class will always minimally have the constructor defined in the following sample policy.
struct SamplePolicy
{
SamplePolicy(const ExpensiveType& expensiveType)
: m_开发者_如何学CexpensiveType(expensiveType) { }
void DoSomething()
{
m_expensiveType.f();
// ...
}
private:
const ExpensiveType& m_expensiveType;
};
Is it possible to define the constructor of Host
in such a way to call the constructor of each given policy? If the type list was not involved, this is very easy since the type of each policy is explicitly known.
template <typename PolicyA, typename PolicyB>
class Host : public PolicyA, public PolicyB
{
public:
Host() :
m_expensiveType(/* ... */),
PolicyA(m_expensiveType),
PolicyB(m_expensiveType) { }
private:
const ExpensiveType m_expensiveType;
};
The boost::mpl::for_each algorithm looks promising, but I can't wrap my head around how to use it to solve this problem.
If you want this kind of generation, I can only recommend a read of Alexandrescu's Modern C++ Design. There is an entire chapter dedicated to the generation of hierarchy from a typelist. You can also find it on Loki's website: Hierarchy Generators; though you will miss the diagrams and explanations, as well as the process.
For you particular problem, this seems pretty straightforward.
// Helper
struct nil
{
};
template < class Head, class Tail = nil>
struct SH: Head<Tail> /* for SimpleHierarchy */
{
SH(const ExpensiveType& e): Head(e), SH<Tail>(e) {}
};
template<>
struct SH<nil,nil>
{
SH(const ExpensiveType& e) {}
}:
// Policies
class A
{
public:
A(const ExpensiveType& e) : T(e), m_e(e) {}
private:
const ExpensiveType& m_e;
};
class B
{
public:
B(const ExpensiveType& e) : T(e), m_e(e) {}
private:
const ExpensiveType& m_e;
};
class C
{
public:
C(const ExpensiveType& e) : T(e), m_e(e) {}
private:
const ExpensiveType& m_e;
};
// Use
// nesting example
typedef SH<A, SH<B,C> > SimpleHierarchy;
// Your example, revisited
template <class A, class B>
class Host: SH<A,B>
{
public:
Host(const ExpensiveType& e): SH<A,B>(e), m_e(e) {}
private:
const ExpensiveType& m_e;
};
Of course, this is a sketch only. The main problem here is the extensibility. If you read Alexandrescu's book, you'll learn much more, and if you don't have the time, do take a peak at the source code, that might prove just what you need.
There are ways to do it directly from the mpl::vector
, the only thing to realize is that you cannot do this with a big MI single-layer, but you can add many layers.
Here, I chose not to add complexity at the Policy level (they are not templatized) and to rely on MI (dual) at each level instead. You could make it purely linear, but templatizing your policies means that you cannot define them in a source file.
Also note that this approach can be adapted to take a mpl::vector
directly, but this would involve the use of meta-template programming operations: back
, pop_back
and empty
at the very least, which might obfuscate the code more than they actually help.
I could not resist the temptation to see how it could be done with inherit_linearly
.
Turns out to be not that bad, IMHO:
template<class Base, class Self>
struct PolicyWrapper : Base, Self
{
PolicyWrapper(const ExpensiveType& E)
: Base(E), Self(E)
{}
};
struct EmptyWrapper
{
EmptyWrapper(const ExpensiveType& E)
{}
};
template <typename PolicyTypeList = boost::mpl::vector<> >
class Host :
public inherit_linearly<
PolicyTypeList,
PolicyWrapper<_1, _2>,
EmptyWrapper
>::type
{
typedef typename inherit_linearly<
PolicyTypeList,
PolicyWrapper<_1, _2>,
EmptyWrapper
>::type BaseType;
public:
Host() : BaseType(m_expensiveType)
{}
private:
const ExpensiveType m_expensiveType;
};
A warning though: Passing a reference to an uninitialized member like what is done in the Host ctor is very fragile. If, for example, one writes a Policy like this:
struct BadPolicy
{
BadPolicy(const ExpensiveType& E)
: m_expensiveType(E)
{}
ExpensiveType m_expensiveType;
};
bad things will happen, as the copy ctor of ExpensiveType will be invoked with an uninitialized object.
As mentioned in the comment, you need to chain the constructor calls. For that, every type in the derivation chain has to know what type its derived from - to allow for arbitrary derivation sequences we need to make that types templates so their base can be any type.
This allows us to refer to the base and explicitly call its constructors.
I scetched out a basic example, but did end up not using boost because mpl::vector
expects known types and i needed to hand it template template parameters. Instead i used a custom typelist that supports template template parameters and implicitly derives.
struct expensive {};
// derivation list
struct nil {}; // list end
struct Noop { // do nothing on end of derivation chain
Noop(expensive& e) {}
};
template<template <typename T> class H, typename L>
struct DL {
typedef L tail;
typedef H<typename tail::head> head;
};
template<template <typename T> class H>
struct DL<H, nil> {
typedef H<Noop> head;
};
// example types
template<class T>
struct A : T {
A(expensive& e) : T(e) {}
};
template<class T>
struct B : T {
B(expensive& e) : T(e) {}
};
// derivation chain usage example
typedef DL<A, DL<B, nil> > DerivationChain;
class User : DerivationChain::head
{
public:
User(expensive& e) : DerivationChain::head(e) {}
};
int main(int argc, char** argv)
{
expensive e;
User u(e);
}
Create a parameterised constructor and pass pameters to it. In this way you could acheive two things simultaneouly. 1) Constructor overloading 2) Avoid call to default constructor.
精彩评论