2

Baseと呼ばれるポリモーフィックな基本クラスと、Baseから継承するクラスDerived1とDerived2がある場合。次に、boost :: lambdaを使用して、ある種のファクトリを作成できます。何かのようなもの:

typedef boost::function<Base *()> Creator;
std::map<std::string,Creator> map1;
map1["Derived1"] = boost::lambda::new_ptr<Derived1>();
map1["Derived2"] = boost::lambda::new_ptr<Derived2>();

(これは実際のコードではありません。問題を説明しようとしているだけです。)

これは機能するので、文字列を使用してマップ内でルックアップを実行し、次にラムダ関数を呼び出してそのクラスをインスタンス化できます。すべて良い。

これに伴う問題は、生のポインターを扱っていることです。私はスマートポインター(std :: shared_ptr)を使用したいと思います。

だから私がから変更した場合:

typedef boost::function<Base *>() Creator;

に:

typedef boost::function<std::shared_ptr<Base> >() Creator;

それから私はここから立ち往生しています。boost :: lambda::bindをboost::lambda :: new_ptrと組み合わせて使用​​してみましたが、運が悪く、過去のコンパイルエラーを取得できません。(テンプレート関連のエラー出力の膨大な連なり。)

StackOverflow内の他の同様のメッセージを確認しました。boost::bindとboost::lambda :: new_ptrを使用してshared_ptrコンストラクターを返すのは近いですが、そのソリューションを適用しようとすると、上記のテンプレートエラーが発生します。

サンプルコードと実際のエラーが役立つ場合は喜んで提供しますが、上記の情報で十分であることを願っています。GCC4.6ではboost1.47.0を使用し、Fedora15では4.7スナップショットを使用しています。

4

4 に答える 4

1
class Base { 
public:
    virtual ~Base() = 0;
};
Base::~Base() {}

class Derived1 : public Base {};
class Derived2 : public Base {};

typedef boost::shared_ptr<Base> BasePtr;

typedef boost::function<BasePtr()> Creator;
template <typename T>
Creator MakeFactory()
{
    namespace la = boost::lambda;
    return la::bind( 
        la::constructor<BasePtr>(), 
        la::bind(la::new_ptr<T>()));
}

int _tmain(int argc, _TCHAR* argv[])
{
    std::map<std::string,Creator> map1;    
    map1["Derived1"] = MakeFactory<Derived1>();
    map1["Derived2"] = MakeFactory<Derived2>();
    BasePtr p1 = map1["Derived1"]();
    BasePtr p2 = map1["Derived2"]();

    return 0;
}

しかし、あなたが書くことができるのになぜ問題に行くのですか?

template <typename T>
BasePtr MakeFactoryImpl()
{
    return BasePtr(new T());
}
template <typename T>
Creator MakeFactory()
{
    return Creator(&MakeFactoryImpl<T>);
}
于 2011-08-24T08:34:03.277 に答える
1

これは一般的な問題です。2つのタイプが(この場合は継承によって)関連しているという事実は、これら2つのタイプを使用したテンプレートのインスタンス化が同じ関係を維持していることを意味するものではありません。

解決策は、常にを返すことです。これは、現在のバージョンと意味的に互換性のある、または任意の派生型shared_ptr<Base>への両方のポインターを保持できるためBaseです(つまり、両方のバージョンで、呼び出し元は(smart)-pointer-toをBase取得します。

余談shared_ptrですが、スマートポインターの選択をすべてのユーザーに強制しているので、工場から戻ることは避けたいと思います。生のポインター(ユーザーは選択できますが、状況によっては危険です)を返すか、または、unique_ptrまたは、さらにauto_ptrは安全であり、ユーザーが別のメカニズムを選択できるようにする(つまり、関数が、を返す場合auto_ptrは、ユーザーは、を実行することでを使用できますがshared_ptrshared_ptr<Base> p( f().release() );その逆はできません(によって管理されているメモリを解放して、別のスマートポインタで使用するshared_ptrことはできません。

于 2011-08-24T08:34:07.617 に答える
0

この手っ取り早いリターンタイプアダプタは、リターンタイプをからDerived*に変換するだけでBase*なく、任意の変換可能なタイプ間で変換するのに適しています。簡単にするために、function-objectは引数を取りません。C ++ 11の可変個引数テンプレートを使用すると、任意の引数処理を簡単に追加できるはずです。自由にこれを改善してください。

template <typename ToType>
class return_type_adapter
{    
    template <typename toType>
    class return_type_adapter_impl_base
    {
      public:
        virtual toType call() = 0;
    };

    template <typename toType, typename Func>
    class return_type_adapter_impl : public return_type_adapter_impl_base<toType>
    {
      public:
        return_type_adapter_impl (Func func) : func(func) {}
        toType call() { return toType(func()); }
      private:
        Func func;
    };

    boost::shared_ptr<return_type_adapter_impl_base<ToType> > impl_base;

  public:
    ToType operator() () { return impl_base->call(); }

    template <typename Func>
    return_type_adapter (Func func) :
        impl_base(new return_type_adapter_impl<ToType, Func>(func)) {}
};
于 2011-08-24T09:32:38.140 に答える
0
map1["Derived1"] = boost::lambda::bind(
    boost::lambda::constructor<boost::shared_ptr<Base>>(),
    boost::lambda::bind(
        boost::lambda::new_ptr<Derived1>()));
map1["Derived2"] = boost::lambda::bind(
    boost::lambda::constructor<boost::shared_ptr<Base>>(),
    boost::lambda::bind(
        boost::lambda::new_ptr<Derived2>()));

しかし正直なところ、これは複雑さのレベルであり、ブーストラマを使用することはもはや意味がありません。より簡単な解決策:

template<typename DerivedType>
boost::shared_ptr<Base> makeDerived() {
    return boost::shared_ptr<Base>(new DerivedType);
}
[...]

    map1["Derived1"] = makeDerived<Derived1>;
    map1["Derived2"] = makeDerived<Derived2>;
于 2011-08-24T09:36:00.713 に答える