2011-08-30 31 views
0

是否可以解決以下使用mpl在運行時選擇參數的方案?在運行時選擇ctor參數

struct A { 
    A(int number) { /* use number */ } }; 
struct B { }; 

template <typename T, int n> 
struct A_or_B_Holder { 
    A_or_B_Holder() : _t(/* void or 'n', depends on T */) { } 
private: 
    T _t; 
}; 

A_or_B_Holder<B, void> b; 
A_or_B_Holder<A, 3> a; 

理想的情況下,

A_or_B_Holder<B> b; 
A_or_B_Holder<A, 3> a; 
+0

聽起來像一個升壓變體... –

+0

正在爲A_or_B_Holder創建專門化嗎? –

+0

專業化是不可能的 - 我必須爲類型T,T_1,T_2,...等每個私人成員創建許多專業化。我想要的是指導模板,在一種情況下,我希望T成員將被創建爲「無效」參數,而另一個成員爲「3」。 –

回答

1

你的第一個問題是:void是一個類型,而不是一個整數。您可以使模板接受兩種類型,第二種是boost::mpl::int_void

然後你可以專門化整個結構,或者你可以把數據成員放在一個基類中並且專門化它。

#include <boost/mpl/int.hpp> 

struct A { 
    A(int number) { /* use number */ } }; 
struct B { }; 

template <class T, class Value> 
struct A_or_B_Holder_Base{ 
    A_or_B_Holder_Base(): _t(Value::value) {} 
protected: 
    T _t; 
}; 

template <class T>  
struct A_or_B_Holder_Base<T, void> { 
    A_or_B_Holder_Base(): _t() {} 
protected: 
    T _t; 
}; 

template <typename T, typename Value> 
struct A_or_B_Holder : public A_or_B_Holder_Base<T, Value> { 

}; 

using boost::mpl::int_; 
A_or_B_Holder<A, int_<3> > x; 
A_or_B_Holder<B, void> y; 
A_or_B_Holder<A, void > w; //error, no default constructor 
A_or_B_Holder<B, int_<3> > z; //error, no int constructor 

更自然可能是不要求的參數是一個編譯時間常數(因爲你是無論如何轉動編譯時常到一個運行時間變量)。只是重載構造函數。

struct A { 
    A(int number) { /* use number */ } }; 
struct B { }; 


template <typename T> 
struct A_or_B_Holder { 
    A_or_B_Holder() : _t() { } 
    A_or_B_Holder(int number): _t(number) {} 
private: 
    T _t; 
}; 

A_or_B_Holder<B> b; 
A_or_B_Holder<A> a(3); 
+0

您還應該添加一個'template struct Value {enum {value = val};};'和一些示例使用代碼。 –

+0

另外,T類型的警告必須是可複製構建的。 –

+0

@Mooing:從所有我可以看到,A和B ** **是可複製構建的。但是對於編輯而言,編譯時常量參數在**不是必需**的整個嘗試中似乎存在缺陷。 – UncleBens

0

我認爲,通過不同的參數在運行時是不可能的。你必須有一個所有T類型都有的標準構造函數。你可以從std::vector<void*>構造所有的T類型,並使用它來傳遞可變數量的變量類型參數,但這是危險的超級

但是,您的示例似乎實際上是在編譯時決定,而不是運行時,這是可以解決的。

const int NO_INT_PARAM=INT_MIN; 
template <typename T, int n> 
struct A_or_B_Base { 
    A_or_B_Holder() : _t(n) { } 
private: 
    T _t; 
}; 
template <typename T> 
struct A_or_B_Base<T, NO_INT_PARAM> { 
    A_or_B_Holder() : _t() { } 
private: 
    T _t; 
}; 
template <typename T, int n=NO_INT_PARAM> 
struct A_or_B_Holder : A_or_B_Base<T, n>{ 
    A_or_B_Holder() : A_or_B_Base() { } 
    /* other functions*/ 
}; 

A_or_B_Holder<A, 3> a; //uses A(3) constructor 
A_or_B_Holder<B> b; //uses B() constructor 
A_or_B_Holder<A> c; //compiler error! A() doesn't exist! 
A_or_B_Holder<B, 5> d; //compiler error! B(5) doesn't exist! 
A_or_B_Holder<B, NO_INT_PARAM> e; //same as b, uses B() constructor 
0

你可以使用一個Boost.Variant

#include <boost/variant.hpp> 

struct A 
{ 
}; 

struct B 
{ 
    B(int) 
    { 
    } 
}; 

int main() 
{ 
    boost::variant<A, B> val; 

    if (/*some condition*/) 
    { 
     val = A(); 
    } 
    else 
    { 
     val = B(5); 
    } 
} 

如果您更感興趣的是,這是如何實現的,而不是你能幹什麼用的,我建議你檢查出Boost.AnyBoost.Variant的實現。

+0

在發佈此消息後,根據Bob對UncleBen的回答的評論來判斷,可能需要其中一些成員函數。 –