2

シンプルな C++ 構文でシンプルなファクトリ メソッドを作成したいと思います。

void *createObject(const char *str,...)
{
  if(!strcmp("X",str))
     return new X(...);
}

これの構文がわかりません。テンプレートのメタプログラミングを調べて mpl::vectors を使用していますが、この構文を継承する方法がわかりません。できれば C の va_lists を使用することは本当に避けて、上記のようなクリーンな構文を使用したいと考えています。

4

4 に答える 4

8

これはC++11でのより良いアプローチです:

template< typename ...Args >
std::shared_ptr<void> createObject( std::string const& name, Args&& ...args )
{
    if( name == "X" )
    {
        return try_make_shared< X >( std::forward< Args >( args )... );
    }
    /* other cases here*/

    return nullptr;
}

template< typename T, typename ...Args >
typename std::enable_if<
    std::is_constructible< T, Args >::value
  , std::shared_ptr< T >
>::type try_make_shared( Args&&... args )
{
    return std::make_shared< X >( std::forward< Args >( args )... );
}
template< typename T, typename ...Args >
typename std::enable_if<
    !std::is_constructible< T, Args >::value
  , std::shared_ptr< T >
>::type try_make_shared( Args&&... args )
{
    throw std::invalid_argument( "The type is not constructible from the supplied arguments" );
    return nullptr;
}

あなたのコードとの違いは

  • 省略記号引数の代わりに可変個引数テンプレート関数を使用するため、パラメーターの数と型はコンパイル時に引き続き使用できます (型チェックを失うことはありません)。さらに、POD 以外の型でこの関数を呼び出すことができます。

  • shared_ptr<void>プレーンの代わりに a を返しますvoid*。これにより、ファクトリ内から、オブジェクトへのすべての参照がなくなった後にオブジェクトをクリーンアップする方法を制御できます。deleteユーザーは、標準を呼び出す必要があるかどうか、またはdeleteObjectファクトリのメソッドを呼び出す必要があるかどうかを知る必要も気にする必要もありません。

更新:を提案する場合は、ここで aがテーブルにもたらす可能性についてunique_ptr読むことができます。-ly に割り当てられたオブジェクトへのポインターのみを返す制限付きファクトリは、 .shared_ptrnewunique_ptr

于 2013-01-01T20:08:23.413 に答える
0

素敵なC++11可変個引数テンプレートを使用してオブジェクトを作成する方法に関するコード(K-balloの回答に見られるように)に加えて、この回答は、プロジェクト内のクラスのセットを処理する方法を示しています。この方法は大きなハックであり、何をしているのかがわかっている場合にのみお勧めします。ただし、プロジェクトに新しいクラスを追加する場合は、すべてのクラスを一覧表示する1つのファイルに追加するだけでよいため、プロジェクトが巨大になった場合は、概要を維持するのに役立ちます。

このアプローチ、クラスを複数回リストする必要がある場合std::string className()、たとえば、C ++実行時型情報を使用せずにクラスの名前を返すなど、関数も必要な場合にのみ使用してください。プロジェクト内のすべてのクラスをリストする必要があるこのような関数はすべて、以下と同様の方法で実装できます。

classes.h

/* For every class in your project which should be creatable through your
 * factory, add a line here. */
CLASS(Foo)
CLASS(Bar)
CLASS(Baz)

factory.cpp

template< typename ...Args >
std::shared_ptr<void> createObject( std::string const& name, Args&& ...args )
{
    // Define what code to insert for every class:
#define CLASS(T) \
    else if(name == #T) \
        return std::make_shared<T>(std::forward(args)...);

    // List all cases:
    if(0) /*do nothing*/;  // <-- needed because the macro uses else if
#include "classes.h"
#undef CLASS

    return nullptr;
}
于 2013-01-01T20:26:05.343 に答える
0

私が最終的に使用した解決策は、テンプレート化されたパラメーターを使用して 0、N 個のシングルトンを作成することでした。これは、N = 8 でかなりうまく機能しています。少し醜いですが、一度だけ実行する必要があります。

于 2013-01-05T12:58:39.250 に答える
0

可変引数テンプレートを使用できず、C スタイルの可変引数を使用したくない場合、唯一のオプションは、引数の一般的な表現を考え出すことです。

boost::shared_ptr<void> createObject(const char *str,
                                     int argc, const char *argv[])
{
  if(!strcmp("X",str))
     return new X(argc, argv);
  if(!strcmp("Y",str))
     return make_Y(argc, argv);
}

に示されているようにY、コンストラクターをオプション形式に結合するのではなく、引数の処理をファクトリー関数に分割することが賢明な場合があります。たとえば、プロパティ マップまたは Boost プログラム オプションに切り替えたい場合があります。

于 2013-01-01T21:21:29.537 に答える