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_expensiveType(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.
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.