簡體   English   中英

具有可變參數的C ++模板類構造函數

[英]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表示帶有變量參數的模板。 更多

構造函數中的變量參數的問題是:

  • 你需要cdecl調用約定(或另一個可以處理varargs)
  • 你不能為構造函數定義cdecl(在MSVS中)

所以“正確”的代碼(MS)可能是:

template < typename T, uint C > __cdecl Vector< T, C >::Vector( T, ... )

但編譯器會說:

構造函數/析構函數的非法調用約定(MS C4166)

在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM