いくつかのパラメーターを含むオブジェクト(ダイアグラムと呼ばれる)で構成されるプログラミングの問題を解決しようとしています。各パラメーター(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抽象基本クラスにテンプレートパラメータを含めることはできません。どんな助けも大歓迎です。
追伸boost :: anyを使用する柔軟性がありません。
あなたはとても親しくなりました。彼らは便利だから私はいくつかのビットを追加しました
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
に正しいデストラクタを設定し、コピー不可、コピー不可に設定してください。
以下の実装ではいくつかの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
。
また、 Sean Parentの値のセマンティクス talkで説明されているものに非常に近いものです。