2012-12-20 150 views
17

我想解決一個包含一個對象(稱之爲圖),包含幾個參數的編程問題。每個參數(Parameter類)可以是幾種類型之一:int,double,complex,string - 僅舉幾例。C++類與模板成員變量

所以我的第一個直覺就是將我的Diagram類定義爲具有模板參數的向量,它看起來像這樣。

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

這不會編譯,我明白爲什麼。因此,基於這些建議How to declare data members that are objects of any type in a class此頁面上,我修改我的代碼看起來像:

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抽象基類中不可能有模板參數。任何幫助是極大的讚賞。

P.S.我沒有使用boost :: any的靈活性。

+2

您不能虛擬設置參數爲任何值,您需要將其轉換爲相應的「參數」類型或刪除該對象並創建一個新對象 –

+3

不要使用setter,然後使用構造函數你總是可以做'v.push_back(新參數(my));' –

+1

爲什麼不把它們轉換成普通類型並在需要時轉換回來?這就是通常這樣的事情。 – KillianDS

回答

25

你離得很近。我加了幾個位,因爲他們是得心應手然後

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具有正確的析構函數,並使其不可複製構建,並且不可複製分配。

+1

不得不對你的測試代碼做一些小的修改,但是這個效果很好。 – endbegin

+0

@endbegin:你必須做出什麼樣的改變?如果我的答案有錯誤,我會爲將來有類似問題的人修復它們。 –

+1

@endbegin:作爲一個說明,提高:: any'作品 –

3

下圖的實現使用了一些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's value semantics談話中描述的內容非常接近。

+0

我覺得'參數'類是不需要的,你沒有提供(明確的)方法來完成賦值,重新分配或獲取隱藏數據。 :(但是既然你有它,爲什麼你不能複製? –

+0

這使得在一個'Diagram'中意外地存儲一個臨時引用變得非常容易 – aschepler

+0

@aschepler謝謝,我在編碼時考慮過這個問題, remove_reference' – pmr