7

オブジェクトを作成するためのファクトリ関数を実装したいと考えています。私のオブジェクト テンプレートは次のようになります。

template <typename TA, typename TB>
struct MyImpl : public MyInterface
{
    // content
};

私の工場は次のようなものです:

MyInterface* factory(char ta, char tb)
{
    if(ta == 'c' && tb == 'c')
    {
        return new MyImpl<char, char>();
    }
    if(ta == 'c' && tb == 's')
    {
        return new MyImpl<char, short>();
    }
    if(ta == 's' && tb == 'c')
    {
        return new MyImpl<short, char>();
    }
    // and so on ....
}

ファクトリ関数は、コンパイル時に決定できなかった非静的 char データ ( ta, tb) を受け入れる必要があります。それがこのファクトリの要点だと思います。実際、tatbはファイル (またはネットワーク) から読み取られます。

煩わしい 2 レベルの切り替えを避けるための、よりシンプルなソリューションが必要です。

私の質問は、静的パラメーターを使用できないことを除いて、how-would-one-write-a-meta-if-else-if-in-c に似ていると思います。

おそらく、C マクロにフォールバックし、いくつかのマクロ トリックを使用して現在のコードを縮小する必要がありますか?

前もって感謝します!

アップデート

@ロブへの回答:

私の実際のコードは、その中に他の多くのものがあるとより複雑になり、読みにくくなり、多くの面で関連しなくなります。私は疑似コードを正しく取得しようとしています。問題がある場合は、親切にお知らせください:-)。

@Dyngussへの回答:

私の問題は、実際の実装では、ファクトリのパラメーター (ta、tb) の範囲が大きく、10 X ta と 20 X tb のようになり、ta と tb の組み合わせが非常に長くなり、保守が困難になることです。 . したがって、組み合わせ作業を軽減するために少なくとも何らかの方法が必要です。

4

3 に答える 3

13

ここにアイデアがあります:

template <typename T>
MyInterface * factroy(char t)
{
    if (t == 'c') { return MyImpl<T, char>();  }
    if (t == 's') { return MyImpl<T, short>(); }
    // ...
}

MyInterface * factory(char ta, char tb)
{
    if (ta == 'c') { return factroy<char>(tb);  }
    if (ta == 's') { return factroy<short>(tb); }
    // ...
}

可変個引数テンプレートを使用すると、このパターンを任意の数の型引数に拡張できます。たとえば、次のようになります。

struct Base { virtual ~Base() = default; };
template <typename A, typename B, typename C> struct Foo : Base { };

#include <tuple>

template <typename ...Args>
constexpr Base * factory(std::tuple<Args...>)
{
    return new Foo<Args...>;
}

template <typename ...Args, typename ...Char>
constexpr Base * factory(std::tuple<Args...>, char t, Char ... ts)
{
    return t == 'c' ? make(std::tuple<char,      Args...>(), ts...)
         : t == 's' ? make(std::tuple<short int, Args...>(), ts...)
         : t == 'i' ? make(std::tuple<int,       Args...>(), ts...)
         : t == 'l' ? make(std::tuple<long int,  Args...>(), ts...)
         : nullptr;
}

使用法:auto p = factory(std::tuple<>(), 'c', 's', 'l');

于 2012-09-24T14:02:16.453 に答える
0

Impl コンストラクターを new Impl(new InnerImpl) に分離できる場合は、スイッチをマップに置き換える非常に複雑なソリューションの可能性があります。

  struct Creator {
     virtual ~Creator(){};
     virtual Interface *create(InterfaceInner *) = 0;
     virtual InterfaceInner *createInner() = 0;
  }

  std::Map<char, Creator *> creatorMap;

  template<char T>
  struct Factory {
     Factory() {
       creatorMap.insert(T, &this->creator);
    }
  }


  template<>
  struct Factory<'s'> {
    struct ShortCreator : public Creator {
     virtual Interface *create(InterfaceInner *inner) {return new Impl<short>(inner);}
     virtual InterfaceInner *createInner(return new ImplInner<short>());
    } creator;
  }




  Factory<'s'> shortFactory;
  Factory<'c'> charFactory;

  creatorMap[ta].create(creatorMap[tb].createInner());
于 2012-09-24T15:02:04.880 に答える
0

どうですか:

MyInterface* factory(char ta, char tb)
{
    switch( ta << 8 | tb )
    {
    case 'cc': return MyImpl<char, char>();
    case 'cs': return MyImpl<char, short>();
    case 'sc': return MyImpl<short, char>();
    // and so on ....
    }
}

注: これは、Intel/AMD x86 および x64、エンディアンが異なる CPU (PPC など) で正常に動作します。スワップtaして、次tbのようにする必要がありますswitch( ta | tb << 8 )

于 2012-09-24T15:59:26.507 に答える