2012-03-20 53 views
1

我試圖編譯克++下面的程序 - 4.7(20120228-1):模板偏特擴展到外類型的結果在歧義

#include <cstdlib> 
#include <tuple> 

template<typename X> struct Y {}; 

template<typename T, size_t Level, size_t TermLevel> struct A; 

// (B) dummy for T=tuple<int, Ts...> just to show it works for simple expansions 
template<typename ... Ts, size_t Level, size_t TermLevel> 
struct A<std::tuple<int, Ts...>, Level, TermLevel> 
{ 
    A<std::tuple<int, Ts...>, Level+1, TermLevel> value; 
}; 

template<typename ... Ts, size_t Level> 
struct A<std::tuple<int, Ts...>, Level, Level> {}; 


// (C) ambiguous partial specialization 
template<typename ... Ts, size_t Level, size_t TermLevel> 
struct A<std::tuple<Y<Ts>...>, Level, TermLevel> 
{ 
    A<std::tuple<Y<Ts>...>, Level+1, TermLevel> value; 
}; 

template<typename ... Ts, size_t Level> 
struct A<std::tuple<Y<Ts>...>, Level, Level> {}; 


int main(int argc, const char *argv[]) 
{ 
    A<std::tuple<int, float, int>, 0, 5> tint; 
    A<std::tuple<Y<int>, Y<float>>, 0, 1> tn; 
    return 0; 
} 

這導致歧義如下:

g++-4.7 -g -O0 -std=c++0x specialization_orig.cc -o specialization_orig 
specialization_orig.cc: In instantiation of 'struct A<std::tuple<Y<int>, Y<float> >, 0ul, 1ul>': 
specialization_orig.cc:33:43: required from here 
specialization_orig.cc:23:49: error: ambiguous class template instantiation for 'struct A<std::tuple<Y<int>, Y<float> >, 1ul, 1ul>' 
specialization_orig.cc:21:8: error: candidates are: struct A<std::tuple<Y<Ts>...>, Level, TermLevel> 
specialization_orig.cc:27:8: error:     struct A<std::tuple<Y<Ts>...>, Level, Level> 
specialization_orig.cc:23:49: error: 'A<std::tuple<Y<Ts>...>, Level, TermLevel>::value' has incomplete type 
specialization_orig.cc:6:61: error: declaration of 'struct A<std::tuple<Y<int>, Y<float> >, 1ul, 1ul>' 

這是因爲一種奇怪的可變參數參數擴建工程的論證組的簡單擴大,而是作爲一個可變參數包擴展到嵌套一些其他的模板類型中一旦出現故障。

這是簡單的編譯器瘋狂還是我做什麼可怕的錯誤?

+0

ICC拒絕這一代碼以及與 「錯誤:一個以上的部分特類的模板參數列表匹配 」A <性病::元組,Y >,1UL,1UL>「 」 A <性病::元組 ...>,水準儀,TermLevel>」 「A <性病::元組 ...>,級別,級別>」 A <性病::元組 ...> Level + 1,TermLevel> value;「,但CLang接受它。任何人只要有科莫或新的足夠VC++可以試試這個,因爲我沒有獲得VS2013和科莫嘗試,它出的是跌? – LThode 2014-11-12 20:15:09

回答

0

它看起來像一個GCC的bug,因爲不確定性消失,如果你有一個固定數量的參數替換參數包:http://ideone.com/6D4Fi

這類含糊不清的也可以使用std::enable_if解決。

/* add "typename = void" anonymous parameter which enables individual partial 
    specializations by matching the void result in std::enable_if<>::type. */ 
template<typename T, size_t Level, size_t TermLevel, typename = void> struct A; 

// No enable_if needed here: always enabled if the levels are equal. 
template<typename ... Ts, size_t Level> 
struct A<std::tuple<int, Ts...>, Level, Level, void> {}; // just pass void 

// Use enable_if to disable in case the levels are equal. 
template<typename ... Ts, size_t Level, size_t TermLevel> 
struct A<std::tuple<Y<Ts>...>, Level, TermLevel, 
    typename std::enable_if< Level != TermLevel >::type > 
+0

當然,'enable_if'總是一個選項。儘管我認爲在這種情況下不應該有必要。首先是因爲專門化(C)到'template struct A ...>,1,1> {};'也沒有幫助,因爲它沒有幫助,牛逼抱怨(B)應產生相同的不確定性下你的解釋 – ignatz 2012-03-21 09:57:19

+0

@ignatz:啊,原來是他!必須要有一條規則,即使用較少的模板參數的功能更專業化,否則它們將同樣專用。我沒有時間,現在回顧:V(反正我會用'enable_if'去,因爲它是一個權宜之計,明顯的修復我覺得你只是偶然在GCC的bug也消失了,如果你消除。參數包:http://ideone.com/6D4Fi – Potatoswatter 2012-03-22 00:04:46