![](/img/trans.png)
[英]Which IDEs and text editors can deduce type of variables declared using auto keyword in C++11
[英]Using C++11 auto keyword to declare two (or more) variables
我有這樣的代碼:
template<class ListItem>
static void printList(QList<ListItem>* list)
{
for (auto i = list->size() - 1, j = -1; i >= 0; --i) {
std::cout << i << ", " << j << ": " << list->at(i) << std::endl;
}
}
當我用g ++ 6.2.1編譯它時,我得到以下編譯器輸出:
test.cpp: In function ‘void printList(QList<T>*)’:
test.cpp:10:7: error: inconsistent deduction for ‘auto’: ‘auto’ and then ‘int’
for (auto i = list->size() - 1, j = -1; i >= 0; --i) {
^~~~
我理解這一點,如果變量有不同的類型,如auto i = 0.0, j = 0;
,但在這種情況下,list是一個指向QList的指針,它的size()方法返回int
, -1
本身也應該是int
。 錯誤消息也有點奇怪。
變量i
和j
僅在此循環中需要,我想將它們聲明為循環參數。 輸入int
而不是auto並不難,但我想知道: auto
不應該用於一次聲明多個變量,或者我在這里遺漏了一些東西而且它確實是錯誤的代碼,或者它可能是編譯器的錯誤?
PS看起來像使用模板函數是這里的關鍵部分,將循環從模板中分解出來不會產生錯誤。 那么,更像是編譯器中的錯誤?
這是GCC中的一個錯誤。
根據[dcl.spec.auto] / 1:
auto
和decltype(auto)
類型指定器用於指定占位符類型,稍后將通過從初始化程序中進行推導來替換該占位符類型。 [...]
模板參數推導的規則永遠不會將類型推斷為auto
。 在這種情況下,扣除的目的實際上是用推導類型替換 auto
。
在示例中, list
具有依賴類型(它取決於模板參數ListItem
),因此表達式list->size() - 1
也具有依賴類型,這使得i
的類型也依賴,這意味着它只會在實例化函數模板printList
解析。 只有這樣才能檢查與該聲明相關的其他語義約束。
根據[temp.res] / 8:
知道哪些名稱是類型名稱允許檢查每個模板的語法。 如果出現以下情況,該計划格式錯誤,無需診斷:
[......這里沒有適用的案例清單......]
否則, 不能為可以生成有效特化的模板發出診斷 。 [ 注意:如果實例化模板,將根據本標准中的其他規則診斷錯誤。 確切地說,這些錯誤被診斷出來是一個實施質量問題。 - 結束說明 ]
(強調我的)
在分析模板printList
的定義時,GCC發出錯誤是錯誤的,因為可以生成明確有效的模板特化。 實際上,如果QList
沒有size()
返回除int
之外的任何特殊化,則i
和j
的聲明在printList
所有實例化中都是有效的。
所有引用均來自N4606 ,(幾乎)當前的工作草案,但上面引用的相關部分自C ++ 14以來沒有改變。
更新:在GCC 6/7中確認為回歸 。感謝TC提供錯誤報告。
更新:原始錯誤( 78693 )已修復即將發布的6.4和7.0版本。 它還揭示了GCC處理此類構造的方式的其他一些問題,導致另外兩個錯誤報告: 79009和79013 。
正如我對你的回答的評論所述,我同意你所提出的分析。
最簡單的問題形式( 演示 ):
template<class T>
void foo (T t) {
auto i = t, j = 1; // error: inconsistent deduction for ‘auto’: ‘auto’ and then ‘int’
}
int main () {}
對於模板,編譯器在其第一階段,檢查基本語法而不實例化它。 在我們的例子中,我們永遠不會調用foo()
。
現在,在上面的例子中, i
的decltype(auto)
仍然是auto
,因為依賴類型T
是未知的。 但是, j
肯定是int
。 因此, 編譯器錯誤是有道理的 。 當前行為(G ++> = 6),可能是也可能不是錯誤。 這取決於我們對編譯器的期望。 :-)
但是,這個錯誤不能被譴責。 以下是C ++ 17草案的支持標准引用:
7.1.7.4.1占位符類型扣除
4 如果占位符是自動類型說明符,則使用模板參數推導的規則確定推斷類型T替換T。 通過用新發明的類型模板參數U替換auto的出現來從T獲得P.
C ++ 14標准中的相同內容與7.1.6.4 / 7相同。
為什么在第一個模板檢查中報告此錯誤?
我們可能正確地爭辯說,為什么編譯器在第一次語法檢查本身中如此“迂腐”。 既然,我們沒有實例化,那就不應該沒問題! 即使我們實例化,也不應該只為有問題的調用提供錯誤!
這就是g ++ - 5的作用。 他們為什么要費心去改變呢?
我認為,這是一個有效的論點。 使用g ++ - 5,如果我打電話:
foo(1); // ok
foo(1.0); // error reported inside `foo()`, referencing this line
然后,當i
和j
具有不同類型時,編譯器會正確報告錯誤及其層次結構。
然后,我將收到有關該主題的信息。
示例代碼中的問題在於使用模板函數。 編譯器做了模板的通用首先檢查沒有實例它,這意味着類型是模板參數(以及依賴於它們,就像其他模板類型)不知道,和auto
,如果它依賴於那些未知類型推導成再次auto
(或不推斷為某種具體類型)。 它從來沒有在我看來即使扣除后auto
仍然可以auto
。 現在原始的編譯器錯誤文本很有意義:變量j
推導為int
類型,但變量i
在推導后仍然是auto
。 由於auto
和int
是不同的類型,編譯器會生成錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.