31

いくつかのパラメータを含むオブジェクト(ダイアグラムと呼びます)で構成されるプログラミングの問題を解決しようとしています。各パラメーター(Parameterクラス)は、int、double、complex、stringなどのいくつかのタイプのいずれかになります。

したがって、私の最初の本能は、Diagramクラスをテンプレートパラメータのベクトルを持つものとして定義することでした。これは次のようになります。

class Diagram
{
private:
    std::vector<Parameter<T> > v;
};

これはコンパイルされません、そして私はその理由を理解しています。したがって、このページの推奨事項に基づいて、クラス内の任意のタイプのオブジェクトであるデータメンバーを宣言する方法を、次のようにコードを変更しました。

class ParameterBase
{
public:
    virtual void setValue() = 0;
    virtual ~ParameterBase() { }
};


template <typename T>
class Parameter : public ParameterBase
{
public:
    void setValue() // I want this to be 
                    // void setValue(const T & val)
    {
        // I want this to be 
        // value = val;
    }

private:
    T value;
};

class Diagram
{
public:
    std::vector<ParameterBase *> v;
    int type;
};

適切なテンプレートパラメータを使用してsetValue関数を呼び出す方法を理解するのに問題があります。ParameterBase抽象基本クラスにテンプレート化されたパラメーターを含めることはできません。どんな助けでも大歓迎です。

PS私にはboost::anyを使用する柔軟性がありません。

4

2 に答える 2

39

あなたはとても近づきました。便利なので少し追加しました

class ParameterBase
{
public:
    virtual ~ParameterBase() {}
    template<class T> const T& get() const; //to be implimented after Parameter
    template<class T, class U> void setValue(const U& rhs); //to be implimented after Parameter
};

template <typename T>
class Parameter : public ParameterBase
{
public:
    Parameter(const T& rhs) :value(rhs) {}
    const T& get() const {return value;}
    void setValue(const T& rhs) {value=rhs;}    
private:
    T value;
};

//Here's the trick: dynamic_cast rather than virtual
template<class T> const T& ParameterBase::get() const
{ return dynamic_cast<const Parameter<T>&>(*this).get(); }
template<class T, class U> void ParameterBase::setValue(const U& rhs)
{ return dynamic_cast<Parameter<T>&>(*this).setValue(rhs); }

class Diagram
{
public:
    std::vector<ParameterBase*> v;
    int type;
};

ダイアグラムは次のようなことを行うことができます:

Parameter<std::string> p1("Hello");
v.push_back(&p1);
std::cout << v[0]->get<std::string>(); //read the string
v[0]->set<std::string>("BANANA"); //set the string to something else
v[0]->get<int>(); //throws a std::bad_cast exception

あなたの意図は、リソースを所有するポインタをベクトルに格納することであるように見えます。その場合は、正しいデストラクタを使用するように注意し、Diagramコピーを作成できないようにし、コピーを割り当てられないようにしてください。

于 2012-12-20T21:21:15.230 に答える
6

以下の実装では、いくつかのC ++ 11機能を使用していますが、それらを区別することができます。

#include <vector>
#include <memory>

class Parameter
{
private:
  class ParameterBase {
  public:
    virtual ~ParameterBase() {}
    virtual ParameterBase* copy() = 0;
    virtual void foo() = 0;
  };

  template <typename T>
  class ParameterModel : public ParameterBase {
  public:
    // take by value so we simply move twice, if movable
    ParameterModel(const T& t) : t(t) {}
    ParameterModel(T&& t) : t(t) {}
    void foo() { t.foo(); }
    ParameterModel* copy() { return new ParameterModel(*this); }
  private:
    T t;
  };

public:
  template <typename T>
  Parameter(T&& t) 
    : pp(new ParameterModel< typename std::remove_reference<T>::type >(std::forward<T>(t))) {}

  // Movable and Copyable only
  Parameter(Parameter&&) = default;
  Parameter& operator=(Parameter&&) = default;

  Parameter(const Parameter& other) : pp(other.pp->copy()) {};
  Parameter operator=(const Parameter& other) {
    pp.reset(other.pp->copy());
    return *this;
  };

  // members

  void foo() { pp->foo(); }
private:
  std::unique_ptr<ParameterBase> pp;
};


class Diagram
{
public:
  std::vector<Parameter> v;
  int type;
};

struct X {
  void foo() {}
};

struct Y {
  void foo() {}
};

int main()
{
  Diagram d;
  d.v.emplace_back(X()); // int

  // parameters are copyable and can be reassigned even with different
  // impls
  Parameter p = d.v.back();

  Parameter other((Y()));
  other = p;
  return 0;
}

このコードは何をしますか?これは、継承を使用してユーザーからのパラメーターを実装するという事実を隠します。彼らが知る必要があるのは、というメンバー関数が必要なことだけですfoo。これらの要件は、で表されますParameterBase。これらの要件を特定し、にを追加する必要がありますParameterBase。これは基本的にもっと制限的boost::anyです。

また、 SeanParentの値セマンティクスの話で説明されているものに非常に近いものです。

于 2012-12-20T21:02:45.657 に答える