我正在使用提升类型列表以下列方式实现策略模式。
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;
};
Host
类知道如何创建ExpensiveType
的实例,这是一项代价高昂的操作,并且每个策略类都公开了使用它的功能。策略类始终最低限度地使用以下示例策略中定义的构造函数。
struct SamplePolicy
{
SamplePolicy(const ExpensiveType& expensiveType)
: m_expensiveType(expensiveType) { }
void DoSomething()
{
m_expensiveType.f();
// ...
}
private:
const ExpensiveType& m_expensiveType;
};
是否可以以这种方式定义Host
的构造函数来调用每个给定策略的构造函数?如果没有涉及类型列表,这很容易,因为每个策略的类型都是明确知道的。
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;
};
boost::mpl::for_each算法看起来很有希望,但我无法理解如何使用它来解决这个问题。
答案 0 :(得分:4)
如果你想要这种一代,我只能推荐阅读Alexandrescu的Modern C++ Design。整个章节专门用于从类型列表生成层次结构。您也可以在Loki的网站上找到它:Hierarchy Generators;虽然你会错过图表和解释,以及过程。
对于你的特殊问题,这看起来非常简单。
// 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;
};
当然,这只是一个草图。这里的主要问题是可扩展性。如果您阅读Alexandrescu的书,您将学到更多东西,如果您没有时间,请在源代码中找到最高点,这可能证明您需要的东西。
有很多方法可以直接从mpl::vector
进行,唯一要意识到的是你不能用一个大的MI单层来做这件事,但你可以添加很多层。
在这里,我选择不在政策层面增加复杂性(它们没有模板化),而是在每个层面依赖MI(双重)。您可以将其设为纯线性,但是对您的策略进行模板化意味着您无法在源文件中定义它们。
另请注意,此方法可以调整为直接采用mpl::vector
,但这将涉及使用元模板编程操作:back
,pop_back
和{{1}至少,它可能会比实际帮助更多地混淆代码。
答案 1 :(得分:3)
如评论中所述,您需要链接构造函数调用。为此,派生链中的每个类型都必须知道它派生自何种类型 - 为了允许任意派生序列,我们需要制作类型模板,以便它们的基础可以是任何类型。
这允许我们引用基类并显式调用它的构造函数。
我查出了一个基本示例,但最终没有使用boost,因为mpl::vector
需要已知类型,我需要提交模板模板参数。相反,我使用了支持模板模板参数并隐式派生的自定义类型列表。
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);
}
答案 2 :(得分:3)
我无法抗拒看到inherit_linearly
如何做到的诱惑。
原来并没那么糟,恕我直言:
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;
};
虽然有警告:将引用传递给未初始化的成员,就像在主机中执行的操作一样,非常脆弱。 例如,如果一个人编写这样的政策:
struct BadPolicy
{
BadPolicy(const ExpensiveType& E)
: m_expensiveType(E)
{}
ExpensiveType m_expensiveType;
};
不好的事情会发生,因为ExpensiveType的复制文件将被一个未初始化的对象调用。
答案 3 :(得分:-2)
创建一个参数化构造函数并将参数传递给它。通过这种方式,您可以同时实现两件事。 1)构造函数重载 2)避免调用默认构造函数。