2012-11-22 44 views
21

在使用GCC 4.7.2和Clang 3.1編譯一些C++ 11代碼時,我碰到了一個問題,Clang沒有設法推導出模板參數GCC成功。 在更抽象的形式,代碼看起來是這樣的:作爲模板參數的可變參數模板:演繹適用於GCC,但不適用於Clang

SRC/test.cc:

struct Element { 
}; 

template <typename T> 
struct FirstContainer { 
}; 

template <typename T, typename U = Element> 
struct SecondContainer { 
}; 

template <template <typename> class Container> 
void processOrdinary(Container<Element> /*elements*/) { 
} 

template <template <typename, typename> class Container> 
void processOrdinary(Container<Element, Element> /*elements*/) { 
} 

template <template <typename, typename...> class Container> 
void processVariadic(Container<Element> /*elements*/) { 
} 

int main() { 
    // This function instantiation works in both GCC and Clang. 
    processOrdinary(FirstContainer<Element>{}); 
    // This function instantiation works in both GCC and Clang. 
    processOrdinary(SecondContainer<Element>{}); 
    // This function instantiation works in both GCC and Clang. 
    processVariadic(FirstContainer<Element>{}); 
    // This function instantiation works in both GCC and Clang. 
    processVariadic<SecondContainer>(SecondContainer<Element>{}); 
    // This function instantiation works in GCC but not in Clang. 
    processVariadic(SecondContainer<Element>{}); 
    return 0; 
} 

通過閱讀在§14.3.3實施例和規範的標準的§14.8.2我認爲扣除應該有效,但我不能肯定地說。這是我從大樓得到的輸出:

mkdir -p build-gcc/ 
g++ -std=c++0x -W -Wall -Wextra -Weffc++ -pedantic -c -o build-gcc/test.o src/test.cc 
g++ -o build-gcc/test build-gcc/test.o 
mkdir -p build-clang/ 
clang++ -std=c++11 -Weverything -Wno-c++98-compat -c -o build-clang/test.o src/test.cc 
src/test.cc:34:3: error: no matching function for call to 'processVariadic' 
    processVariadic(SecondContainer<Element>{}); 
    ^~~~~~~~~~~~~~~ 
src/test.cc:21:6: note: candidate template ignored: failed template argument deduction 
void processVariadic(Container<Element> /*elements*/) { 
    ^
1 error generated. 
make: *** [build-clang/test.o] Fel 1 

爲什麼結果不同? GCC是否馬虎,鏗鏘笨拙,我的代碼是否包含未指定的行爲或全部?

+0

我同意你的意見。我在C++ 11最終草稿中看到的所有內容都表明這應該起作用。 14.3.3.3尤其相關。 –

+0

你的例子缺少'typedef int Element;',對吧? – Quuxplusone

+0

不,在代碼的開頭我定義了一個名爲Element的結構體。 – psyill

回答

7

鏘試圖推斷論據此調用:

processVariadic(SecondContainer<Element>{}); 

由於SecondContainer有一個默認的模板參數,這相當於:

processVariadic(SecondContainer<Element, Element>{}); 

因此,執行模版參數推導與P = Container<Element>A = SecondContainer<Element, Element>。它可以立即推斷出Container模板參數是SecondContainer

接下來,它會考慮模板參數。由於參數類型已完全解析,Clang認爲該參數必須具有多個類型,否則扣除不可能成功(它不考慮默認參數)。所以它標誌着扣除失敗。


那麼,應該發生什麼?在[temp.deduct.type]p8的話,

模板類型參數T,一個模板的模板參數TT或模板非類型參數我可以如果PA具有下列形式中的一種來推斷:
[...]
TT<T>
TT<i>
TT<>
其中[...] <T>代表模板參數列表,其中至少一個ARG包含T,<i>表示模板參數列表,其中至少一個參數包含i<>表示模板參數列表,其中參數不包含Ti

爲了匹配模板參數,我們就轉向[temp.deduct.type]p9

如果P有一個包含<T><i>一種形式,那麼相應的模板參數列表P的每個參數Pi與比較相應的參數Ai的相應模板參數列表爲A

這裏有兩件事要注意。一個是,這條規則並沒有說明如果PiAi的長度是不同的長度(因爲它們在這種情況下)會發生什麼情況,而常見的解釋似乎是不檢查不匹配的項目。另一個原因是不應該遵循這個規則,因爲P的形式不包含<T><i>(它只包含<>,因爲其中沒有模板參數)。


所以,鏗鏘拒絕這個代碼是錯誤的。我已經修復它在r169475

相關問題