2015-06-03 58 views
4

我最近開始嘗試各種模板技巧。在這種情況下,我嘗試使用參數包來實現一個類,該類持有由可變參數模板提供的數字序列。可變函數模板中的歧義

不過,我碰到一些問題,做發生在我使用的編譯器(英特爾C++ 14),但其他人一樣GCC。因此,我很困惑哪種編譯器在解釋標準時「更重要」。

這裏是我的代碼:

#include <iostream> 

using namespace std; 

template< size_t... Sequence > 
class CSequence 
{ 
    public: 
     CSequence() 
     { 
      this->generate<Sequence...>(); 
      this->out(); 
     } 

    private: 
     // Recursion end 
     template< size_t N > 
     void generate(size_t sz) 
     { 
      // Create array 
      this->m_Array = new size_t[sz+1]; 

      this->m_Len = sz+1; 

      this->m_Array[sz] = N; 
     } 

     // Recursion segment 
     template< size_t N, size_t... Ns > 
     void generate(size_t sz) 
     { 
      generate<Ns...>(sz+1); 

      this->m_Array[sz] = N; 
     } 

     // Recursion start 
     template< size_t... Ns > 
     void generate() 
     { 
      generate<Ns...>(0); 
     }   

     void out() 
     { 
      for(int i = 0; i < this->m_Len; i++) 
      { 
       std::cout << this->m_Array[i] << " "; 
      } 

      std::cout << std::endl; 
     } 

    private: 
     size_t*  m_Array; 
     size_t  m_Len; 
}; 

int main() 
{ 
    CSequence< 1, 2, 3, 4, 5, 6, 7, 8 > a; 
    std::getchar(); 
} 

這編譯使用我的最終罰款英特爾C++ 14和產生的結果我希望:

1 2 3 4 5 6 7 8 

但在兩者的最新版本CLang和GCC無法編譯:

現在,其實我可以理解失敗的原因:由於參數包可以包含零個元素,典型的呼叫

generate<8>(size_t); 

可以解決既作爲

generate< N = 8, Ns = <> > (size_t) 

and as

generate< N = 8 > (size_t) 

因此導致無法解決的歧義。但事實上,它編譯我的目的,實際上給出了預期的結果,讓我想知道:

  1. 哪個編譯器是「正確的」?顯然與Cang或GCC相比,Intel C++做出了一些額外的決定。這是關於標準的「非法」嗎?還是GCC/CLang只是缺乏?
  2. 有什麼辦法可以規避這種行爲嗎?

請注意,這段代碼被認爲是某種實驗,所以我很滿意這兩種替代策略並修復了這段代碼。

回答

2

這根本不需要遞歸實現。

template< size_t... Ns > 
void generate() 
{ 
    m_Len = sizeof...(Ns); 
    m_Array = new size_t[m_Len] { Ns... }; 
} 

您還可以分配與動態分配,使m_Array實際陣列,並用NSDMI初始化:

size_t m_Array[sizeof...(Sequence)] = {Sequence... }; 
+0

謝謝。我將其標記爲答案,因爲它實際上是一個更好的解決方案,而不僅僅是修復。 – nshct

2

Clang和GCC是正確的,因爲參數包可以包含零個元素,並且沒有爲這種情況定義的部分排序,所以調用是不明確的。

解決這個問題的最簡單方法是讓遞歸案例採用額外的模板參數。這樣,通話是完全明確的:

// Recursion segment 
template< size_t N1, size_t N2, size_t... Ns > 
//    extra param ^^ 
void generate(size_t sz) 
{ 
    generate<N2,Ns...>(sz+1); 
    //add N2 ^^ 

    this->m_Array[sz] = N1; 
} 
+1

...解決這個問題是不使用遞歸的最簡單的方法所有。 –

+0

@ T.C。如果你想分享一種沒有遞歸的方式,隨時發佈另一個答案。我提到我對其他解決方案持開放態度。謝謝。 – nshct