2

DNS名前リゾルバーを作成しています。返されたパケットを解析している間、RRタイプを読み取り、それをスイッチに渡して、派生タイプのクラスRecordを初期化します。レコードタイプは大きな列挙型です。テンプレートの特殊化を使用して、列挙型を構造体にマップします。

template < QueryType n >
struct Struct;

template <> struct Struct< DNS_Q_A > { typedef A Type; };
template <> struct Struct< DNS_Q_CNAME > { typedef CNAME Type; };

template < QueryType n > struct Struct { typedef UNKNOWN Type; };

現在、私は4つのswitchステートメントを持っていますが、これらはすべて非常によく似た処理を行います。つまり、コピーと移動の両方の演算子について、演算子new、配置newを呼び出します。これは維持する必要のある多くのコードです。実行する関数を含むある種のオブジェクトを渡して、型とn個のパラメーターを返すことができるswitchステートメントを1つだけ作成したいと思います。

switchステートメントは次のようになります。

switch ( nType )
{
case DNS_Q_A:
    pInstance = new ( &Container ) Struct< DNS_Q_A >::Type( dynamic_cast< const Struct< DNS_Q_A >::Type& >( Other ) );
    break;
case DNS_Q_CNAME:
    pInstance = new ( &Container ) Struct< DNS_Q_CNAME >::Type( dynamic_cast< const Struct< DNS_Q_CNAME >::Type& >( Other ) );
    break;
}

ご覧のとおり、構造体タイプに依存していることを除けば、それぞれのケースは同じです。これは私に「テンプレート」を叫びますが、オブジェクトを渡す方法がわかりません。

私は4つのスイッチのコーディングに制限されていますか、それとも方法はありますか?「Boost」を引用しないでください。このコードは他のライブラリから独立している必要があります。

解決策:(JanHudecに感謝します)

template< template < class > class Action >
typename Action< Struct< DNS_Q_A >::Type >::result_type
    CreateRecord ( 
        unsigned n,
        typename Action< Struct< DNS_Q_A >::Type >::first_argument_type arg1,
        typename Action< Struct< DNS_Q_A >::Type >::second_argument_type arg2 )
{
    typedef typename typename Action< Struct< DNS_Q_A >::Type >::result_type ReturnType;
    switch ( n )
    {
    case DNS_Q_A:       return static_cast< ReturnType >( Action< Struct< DNS_Q_A >::Type >()( arg1, arg2 ) );
    case DNS_Q_NS:      return static_cast< ReturnType >( Action< Struct< DNS_Q_NS >::Type >()( arg1, arg2 ) );
    /*...*/
    }
}

アクション構造体は次のように定義されています。

template < typename T >
struct Copy : std::binary_function< storage_type&, const Record&, Record* >
{
    Record* operator() ( storage_type& Storage, const Record& Obj )
    {
        return new ( &Storage ) T( dynamic_cast< const T& >( Obj ) );
    }
};
template < typename T >
struct Move : std::binary_function< storage_type&, Record&&, Record* >
{
    Record* operator() ( storage_type& Storage, const Record& Obj )
    {
        return new ( &Storage ) T( dynamic_cast< const T& >( std::move( Obj ) ) );
    }
};

そして、Switchステートメントは次のように置き換えられました。

pInstance = CreateRecord< Copy >( nType, Container, Other );
4

2 に答える 2

2

ファンクターテンプレートを使用して実行する関数テンプレートを作成できます。C ++ 11の可変個引数がない場合、すべてのファンクターは同じ数の引数を必要とするため、それらを構造体にパックするか、無関係な場合はNULLを渡す必要があります。可変個引数テンプレート(まだ使用していないので、正確な構文を覚えておらず、ここでは記述しません)を使用すると、フォームごとに異なる引数を簡単に設定できます。

アイデアは次のようなものです(頭のてっぺんから離れているので、タイプミスがあるかもしれません):

template <template <typename T> class F>
F<Struct<DNS_Q_A>::Type>::return_type RecordCall(RecordType nType, const F<Struct<DNS_Q_A>::Type>::argument_type &arg)
{
    switch(nType)
    {
        case DNS_Q_A:
            return F<Struct<DNSK_Q_A>::Type>()(arg);
        case DNS_Q_CNAME:
            return F<Struct<DNSK_Q_CNAME>::Type>()(arg);
        // ...
     }
}

ここで、次のような個々の関数を記述します。

template <typename T>
struct Clone : std::unary_function<BaseType *, const BaseType *>
{
    BaseType *operator()(const BaseType *source)
    {
        return new<T>(dynamic_cast<const BaseType &>(*source));
    }
}

一緒に組み合わせる:

target = RecordCall<Clone>(source->GetType(), source);

(そして、配置コピー構築のような複数引数フォームのゲッターおよび/またはパック引数を挿入する別の関数でラップします)

これを行う一般的な方法をコピーするには、仮想クローンメンバーメソッドを使用する必要があります。しかし、それは建設には効果がありません。

unary_function編集:内部テンプレート内のreturn型とargument型を(標準ヘルパーを使用して)typedefとして定義しましたが、特にの使用RecordCallが別の関数でラップされる場合は、別のテンプレート引数として渡すことができます。Record *おそらく、returnタイプは、質問で言及されているすべてのケースに当てはまるため、テンプレートパラメーターである必要はありません。

于 2012-06-26T06:38:17.663 に答える
0

私はここで何が達成できないのかを完全には理解していないことを認めなければなりません...ばかげた仮想関数。

class Object {
public:
    virtual Object* clone() const = 0;
    virtual void clone(Container& c) const = 0;

    // ...
};


class A: public Object {
public:
    virtual A* clone() const override { return new A(*this); }
    virtual void clone(Container& c) const override { new (&c) A(*this); }

    // ...
};

次に...スイッチを取り除くだけです:

pInstance = other.clone(container);

そして仕事は終わりました。

于 2012-06-26T06:29:46.287 に答える