4

テンプレート化されたメンバー関数を持つクラスがあります。

class Person
{
  template <typename TItem>
  void DoSomething(TItem item)
  {
    item.Action();
  } 
};

これにより、アクションメンバー関数を使用して任意のアイテムを渡すことができ、そのアイテムを使用してそのアクションを実行できます。だから私はすることができました:

Person person;
BaseballBat bat;
person.DoSomething(bat);

この構造により、任意のタイプのオブジェクトで関数を呼び出すことができます。ただし、任意のタイプのオブジェクトを格納する場合は、クラスをテンプレート化する必要があります。

template <TItem>
class Person
{
public:
  void DoSomething()
  {
    this->Item.Action();
  }

  void SetItem(TItem item)
  {
    this->Item = item;
  }
private:
  TItem Item;
};

Person<BaseballBat> person;
BaseballBat bat;
person.SetItem(&bat);
person.DoSomething();

オブジェクトのタイプを変更するには、Personクラスを再インスタンス化する必要があるため、これは面倒です。

または、親クラスからアイテムを派生させることもできます。

class Person
{
public:
  void DoSomething()
  {
    this->Item.Action();
  }

  void SetItem(TItem* item)
  {
    this->Item = item;
  }

private:
  ParentItem* Item;
};

class ParentItem{};

class BaseballBat : public ParentItem
{}

Person person;
BaseballBat bat;
person.SetItem(&bat);
person.DoSomething();

すべてのアイテムの継承構造を維持する必要があるため、これは厄介です(これは非常に「非GP」のようです)。

問題は、「オブジェクトを含むオブジェクト」の複数のレイヤーがある場合に実際に発生します。つまり、非常に「トップレベル」の呼び出しから含まれるクラスに関数テンプレートの引数を「渡す」必要があります。

class BaseballBat
{
  void DoAction();
};

class Child
{
  template <typename TItem>
  void DoAction(TItem item)
  {
    item.DoAction();
  }
};

class Person
{
  Child child;

  // This is annoying to have to pass the item to the person, who then has to pass it to the child. I'd rather "give" the child an Item, then just be able to call child.DoAction(), where the Person doesn't know anything about the item.
  template <typename TItem>
  void PlayWithChild(TItem item)
  {
    child.DoAction(item);
  }
}

関数テンプレートとオブジェクトをメンバーデータとして保存するというこれら2つのアイデアを正しく組み合わせる方法について誰かがコメントできますか?(上記は、デモンストレーションを試みるための安っぽい例です-それらが意味をなさない場合、またはより良い例がある場合、私はすべての耳です:))。

---------編集---------多分より良い例は私の実際のケースの単純化です。メンバー関数を持つクラスMatcherがあります。

template<typename TDistanceFunctor, typename TPropagationFunctor>
void Matcher::Compute(TDistanceFunctor distanceFunctor, TPropagationFunctor propagationFunctor);

次に、Matcherを使用する別のクラスImageAlgorithmがあります。

template<typename TMatcher>
void ImageAlgorithm::Compute(TMatcher matcher)
{
  matcher.Compute(...); // How do I get the DistanceFunctor and the PropagationFunctor here?
}

私はこれらのものを次のように呼びたいです:

Matcher myMatcher;
.... Setup matcher (how?) ...
ImageAlgorithm algorithm;
algorithm.Compute(myMatcher);

ImageAlgorithm :: Compute呼び出し内のMatcherオブジェクトに到達できるように、ImageAlgorithmオブジェクトを介してDistanceFunctorとPropagationFunctorを「パススルー」する方法がわかりません。もちろん、TDistanceFunctorでMatcherをテンプレート化し、TDistanceFunctorをメンバー変数として格納することはできますが、後で、マッチャーが使用する距離ファンクターを別のタイプの距離ファンクターに変更することはできません。

4

1 に答える 1

1

タイプバリアントメンバーを保持するためにboost::anyを使用してみることができます。

概要から:

boost::any クラス (...) は、任意の値の型のコピーと、その型に対して厳密にその値の安全なチェック付き抽出をサポートします。

編集

ブースト any を使用した格納されたファンクターの呼び出しが問題になることは間違いありません。したがって、別の解決策をお勧めします: std::function (または boost::function) を使用して、ファンクターをラップします。こうすることで、Matcher は関連する構文 (たとえば、パラメーターなし) の関数オブジェクトを保持でき、ファンクターの型をテンプレート化する必要がなくなります。

関数オブジェクトは、OO (少なくともある意味で) と GP の組み合わせを既に行っています。

于 2012-08-11T20:44:48.997 に答える