13

考慮代碼:是否合法,以部分地專門與來自外部類的可變參數模板ARGS可變參數模板內部類

#include <iostream> 

template <class... Ts> 
struct outer { 
    template <class... ITs> 
    struct inner { 
     static constexpr bool value = false; 
    }; 

    template <class... ITs> 
    struct inner<Ts..., ITs...> { 
     static constexpr bool value = true; 
    }; 
}; 

int main() { 
    std::cout << outer<int, float, double>::inner<int, float, double, int>::value << std::endl; 
} 

代碼編譯與鐺++但不與克++,它產生一個錯誤:

temp3.cc:11:11: error: parameter pack argument ‘Ts ...’ must be at the end of the template argument list

struct inner<Ts..., ITs...> { 
    ^

由於我已經建立here內部類的部分專業化應該是合法的。

編輯: 出於完整性很值得補充說,鐺上面的代碼警告說,他可能會與推斷它的參數還沒有這樣做沒有任何問題一個問題...

+0

我完全不知道規則,但是當我得到一個依賴類型的錯誤時,在它有時幫助之前添加'typename'或'template'。試試'struct inner Dani

+0

添加'typename'後我得到'temp3.cc:11:39:錯誤:模板參數1無效' –

+0

請注意,請求的場景仍然可以通過一些額外的模板元編程實現... http:///coliru.stacked-crooked.com/a/0c6c643c8ff5809e(是的,我知道這不是問題,但實施它的挑戰是不可避免的...)。 –

回答

8

這是一個錯誤的gcc 。這是一個完全有效的偏特:

template <class... ITs> 
struct inner<Ts..., ITs...> { 
    static constexpr bool value = true; 
}; 

被推導的模板參數包必須要在後,ITs...滿足這一點。但Ts...不是需要在這裏推斷的包,它只是一個特定的參數包。

此外,GCC編譯幾個等效製劑:

template <class... Ts> 
struct X { 
    template <class... Us> 
    static void foo(Ts..., Us...) { } 
}; 

int main() { 
    X<int>::foo(1, 'c'); 
} 

和:

template <class... Us> 
struct A { }; 

template <class... Ts> 
struct X { 
    template <class... Us> 
    static void foo(A<Ts..., Us...>) { } 
}; 

int main() { 
    X<int>::foo(A<int, char>{}); 
} 

這些等效結構良好的到原始示例。啓發於巴里的回答

+0

我懷疑,但不知道模板類內是否存在專門化背景下的一些特殊規則。這是一個已知的錯誤嗎? –

+4

我確實認爲部分專業化是有意義的,但我不確定書面標準是否允許。 [14.5.5p8.5]說*如果一個參數是一個包擴展(14.5.3),它應該是模板參數列表*中的最後一個參數。這是對部分專業化的特定要求,因此它不適用於您的示例。這看起來更像是一個標準問題,而不是一個編譯器bug。 – bogdan

+0

你應該將bug報告提交給'gcc'。你完成了嗎? – Destructor

0

可能簡單而有效的解決方法:

#include <iostream> 

template <class... Ts> 
struct pack { }; 

template <class... Ts> 
struct outer { 
    template <class IT> 
    struct inner { 
     static constexpr bool value = false; 
    }; 

    template <class... ITs> 
    struct inner<pack<Ts..., ITs...>> { 
     static constexpr bool value = true; 
    }; 
}; 

int main() { 
    std::cout << outer<int, float, double>::inner<pack<int, float, double, int>>::value << std::endl; 
} 

(它仍然在鐺產生警告,雖然)

1

乘着WF的回答,仍然保持相同的主要作爲原題:

#include <iostream> 

template <class... Ts> 
struct pack { }; 

template <class... Ts> 
class outer { 
    template <class IT> 
    struct _inner { 
     static constexpr bool value = false; 
    }; 

    template <class... ITs> 
    struct _inner<pack<Ts..., ITs...>> { 
     static constexpr bool value = true; 
    }; 
public: 
    template <class... ITs> 
    struct inner { 
     static constexpr bool value = _inner<pack<ITs...>>::value; 
    };  
}; 

int main() { 
    std::cout << outer<int, float, double>::inner<int, float, double, int>::value 
      << std::endl; 
} 

它仍然會產生在鐺一個警告,因爲_inner的專用版本無法地推出其...從TS列表中除了... ,IT ......(在struct _inner<pack<Ts..., ITs...>>) - 但是代碼並不要求IT從Ts ...,ITs列表中單獨推導出來,所以這應該沒問題。

在g ++中,它編譯時沒有警告。

代碼:http://coliru.stacked-crooked.com/a/ae3b21dd847450b2

(對於沒有警告也在鐺溶液:http://coliru.stacked-crooked.com/a/0c6c643c8ff5809e)。

相關問題