2013-12-09 28 views
1

我有一個模擬兩維和三維工程問題的科學庫。 2D和3D代碼非常相似,但專門用於2D和3D問題。例如,一個簡單的point類明確地在2D和3D中具有不同的實現。使用variardic模板的與尺寸無關的類

我對c++11非常陌生,但基於我已閱讀的內容,我決定測試新功能以將這些代碼無縫地組合到獨立於維度的框架中。我的第一次嘗試是寫一個簡單的泛型類point如下:

#include <iostream> 

template<unsigned short dim, typename T=double> 
class point{ 
    const T x[dim]; 

public: 
    template<typename... X> 
    point(X... xs): x{xs...} 
    { 
     static_assert(dim>0, "A point needs to at least have one component"); 
    } 

    friend std::ostream& operator<<(std::ostream& os, const point<dim,T>& p) 
    { 
     os << "("; 
     for (unsigned short i=0; i<dim-1; i++) 
      os << p.x[i] << ", "; 
     os << p.x[dim-1] << ")" << std::endl; 

     return os; 
    } 
}; 

int main(){ 
    point<3> p = {3., 4.}; 
    std::cout << p; 
    return 0; 
} 

除了我有兩個問題/疑問,工作正常。首先,爲什麼我需要模板參數TX?爲什麼不告訴編譯器爲variardic構造函數使用相同的模板參數?對我來說,這似乎是一個合理的要求!

其次,如果我曾嘗試point<2> p = {3, 5};,我會在narrowing conversion of ‘xs#0’ from ‘int’ to ‘const double’ inside { } [-fpermissive]處大聲喊叫。爲什麼不能從一個整數初始化一個double?我從來沒有想過這是非法的。這是新的c++11,如果是這樣的解決方法是什麼?

+1

'static_assert'在編譯時完成,所以你不需要在函數中使用它。 –

+0

@JoachimPileborg Interetsing。感謝您的評論。 – GradGuy

回答

0

你可以使用std::initializer_list並使用std::vector而不是數組:

template<unsigned short dim, typename T=double> 
class point{ 
    static_assert(dim>0, "A point needs to at least have one component"); 
    const std::vector<T> x; 

public: 
    point(std::initializer_list<T> xs): x{xs} 
    {} 

    ... 
}; 
+0

但我喜歡編譯器的靜態維度檢查。 'std :: array'是一個更好的選擇,而不是'std :: vector',或者當使用'std :: initializer_list'時沒有希望進行靜態檢查? – GradGuy

+0

@GradGuy不幸的是['std :: array'](http://en.cppreference.com/w/cpp/container/array)沒有一個構造函數採用'std :: initializer_list'(或者任何特定的構造函數完全),所以你回頭使用了一個可變模板構造函數。 –

0

我能夠通過強制編譯器將投輸入回T要解決的問題:

template<unsigned short dim, typename T=double> 
class point{ 
    static_assert(dim>0, "A point needs to at least have one component"); 
    const T x[dim]; 

public: 
    template<typename... X> 
    point(X... xs): x{static_cast<T>(xs)...} {}   
}; 

雖然這只是尷尬,我不理解標準背後的這種變化的基本原理,但這可能對某人有用!

+0

你可以將int轉換爲double,但是你不能在一個braced-init-list中使用int來初始化double,比如int i {42}。雙d {i};'。理由是禁止有損轉換。例如,不是64位'int'的每個值都可以在64位'double'中完全表示。我建議你編寫一個'implicit_cast'函數模板,例如'template to implicit_cast(From && f){return std :: forward (f);}''而不是使用'static_cast',因爲它更接近具有N個參數的'point :: point'類型爲「To」。 – dyp