[英]C++ Template Class Constructor with Variable Arguments
是否可以創建一個帶有可變數量參數的模板函數,例如,在此Vector< T, C >
類構造函數中:
template < typename T, uint C >
Vector< T, C >::Vector( T, ... )
{
va_list arg_list;
va_start( arg_list, C );
for( uint i = 0; i < C; i++ ) {
m_data[ i ] = va_arg( arg_list, T );
}
va_end( arg_list );
}
這幾乎可以工作,但如果有人調用Vector< double, 3 >( 1, 1, 1 )
,則只有第一個參數具有正確的值。 我懷疑第一個參數是正確的,因為它在函數調用期間被強制轉換為double
,而其他參數被解釋為int
,然后這些位被填充為double
。 調用Vector< double, 3 >( 1.0, 1.0, 1.0 )
可得到所需的結果。 有沒有一種首選方式來做這樣的事情?
唉,現在沒有好辦法做到這一點。 大多數需要做類似事情的Boost包使用宏技巧來定義這樣的事情:
template < typename T >
Vector< T >::Vector( T )
{ ... }
template < typename T, uint C >
Vector< T, C >::Vector( T t, C c1 )
{ ... }
template < typename T, uint C >
Vector< T, C >::Vector( T t, C c1, C c2 )
{ ... }
template < typename T, uint C >
Vector< T, C >::Vector( T t, C c1, C c2, C c3 )
{ ... }
宏生成一些設置數(通常約為10個)版本,並提供一種機制來在擴展構造之前更改參數的最大數量。
基本上,這是一個真正的痛苦,這就是為什么C ++ 0x引入了可變長度模板參數和委托方法,可以讓你干凈(安全)地完成這項工作。 在此期間,您可以使用宏來執行此操作,也可以嘗試使用支持(部分)這些新實驗功能的C ++編譯器。 GCC對此很好。
但要注意的是,由於C ++ 0x實際上還沒有出現,所以事情仍然會發生變化,而且您的代碼可能與標准的最終版本不同步。 此外,即使在標准出來之后,也會有5年左右的時間,在此期間許多編譯器只會部分支持標准,因此您的代碼將不會非常便攜。
這段代碼看起來很危險,我認為你對它無法正常工作的分析很明顯,編譯器在調用時無法知道:
Vector< double, 3 >( 1, 1, 1 )
這些應該作為雙打傳遞。
我會將構造函數更改為:
Vector< T, C >::Vector(const T(&data)[C])
相反,讓用戶將參數作為數組傳遞。 另一種丑陋的解決方案是這樣的:
template < typename T, uint C >
Vector< T, C >::Vector(const Vector<T, C - 1>& elements, T extra) {
}
並像這樣調用它(使用某些typedef):
Vector3(Vector2(Vector1(1), 1), 1);
你可以做你想做的事,但不要做,因為它不是類型安全的。 Best傳遞T
的向量或包含這些值的一對迭代器。
template < typename T, uint C >
Vector< T, C >::Vector(int N, ... )
{
assert(N < C && "Overflow!");
va_list arg_list;
va_start(arg_list, N);
for(uint i = 0; i < N; i++) {
m_data[i] = va_arg(arg_list, T);
}
va_end(arg_list);
}
Vector<int> v(3, 1, 2, 3);
這可以更好地解決,因為無論如何所有元素都是均勻類型的。
template < typename Iter, uint C >
Vector< T, C >::Vector(Iter begin, Iter end)
{
T *data = m_data;
while(begin != end)
*data++ = *begin++;
}
int values[] = { 1, 2, 3 };
Vector<int> v(values, values + 3);
當然,你必須確保m_data
有足夠的位置。
您可以使用variadic,variadic表示帶有變量參數的模板。 更多
構造函數中的變量參數的問題是:
所以“正確”的代碼(MS)可能是:
template < typename T, uint C > __cdecl Vector< T, C >::Vector( T, ... )
但編譯器會說:
構造函數/析構函數的非法調用約定(MS C4166)
TypeList是否符合您的需求?
在C ++ 0x中(實際上應該稱為C ++ 1x),您可以使用模板varargs以類型安全的方式實現您想要的(並且您甚至不需要指定參數的數量!)。 但是,在當前版本的C ++(ISO C ++ 1998 with 2003修訂版)中,沒有辦法完成你想要的。 您可以延遲或執行Boost所做的操作,這是使用預處理器宏魔術 ,使用不同數量的參數重復構造函數的定義,直到硬編碼但大的限制。 鑒於Boost.Preprocessor有點復雜,您可以自己定義以下所有內容:
Vector<T,C>::Vector(); Vector<T,C>::Vector(const T&); Vector<T,C>::Vector(const T&, const T&); // ...
但是,由於上面的手工操作很痛苦,你可以編寫一個腳本來生成它。
std::tr1::array
(看起來與你的類似)沒有定義構造函數,可以初始化為聚合(?)
std::tr1::array<int, 10> arr = {{ 1, 2, 3, 4, 5, 6 }};
您還可以查看Boost.Assignment庫。
例如,構造函數可以是
template < typename T, uint C >
template < typename Range >
Vector< T, C >::Vector( const Range& r )
用。創建的實例
Vector<int, 4> vec(boost::assign::cref_list_of<4>(1)(3)(4)(7));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.