4

次の方法でポリシー パターンを実装するために、boost typelist を使用しています。

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アルゴリズムは有望に見えますが、それを使用してこの問題を解決する方法について頭を悩ますことはできません。

4

4 に答える 4

4

この種の生成が必要な場合は、Alexandrescu のModern C++ Designを読むことをお勧めします。タイプリストからの階層の生成に特化した章全体があります。Loki の Web サイトでも見つけることができます: 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ください。backpop_backempty

于 2009-11-04T08:14:36.233 に答える
3

コメントで述べたように、コンストラクター呼び出しをチェーンする必要があります。そのためには、派生チェーン内のすべての型が、その派生元の型を認識している必要があります。任意の派生シーケンスを許可するには、その型テンプレートを作成して、そのベースを任意の型にできるようにする必要があります。
これにより、ベースを参照し、そのコンストラクターを明示的に呼び出すことができます。

基本的な例を抜粋しましたが、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);
}
于 2009-11-04T03:36:58.117 に答える
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;
};

ただし、警告: Host ctor で行われているように、初期化されていないメンバーへの参照を渡すことは非常に脆弱です。たとえば、次のように Policy を記述したとします。

struct BadPolicy
{
    BadPolicy(const ExpensiveType& E)
    : m_expensiveType(E)
    {}

    ExpensiveType m_expensiveType;
};

ExpensiveType のコピー ctor が初期化されていないオブジェクトで呼び出されるため、悪いことが起こります。

于 2009-11-04T15:02:32.763 に答える