簡體   English   中英

使用C ++ 11 auto關鍵字聲明兩個(或更多)變量

[英]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 錯誤消息也有點奇怪。

變量ij僅在此循環中需要,我想將它們聲明為循環參數。 輸入int而不是auto並不難,但我想知道: auto不應該用於一次聲明多個變量,或者我在這里遺漏了一些東西而且它確實是錯誤的代碼,或者它可能是編譯器的錯誤?

PS看起來像使用模板函數是這里的關鍵部分,將循環從模板中分解出來不會產生錯誤。 那么,更像是編譯器中的錯誤?

現場演示 - 最少的代碼

這是GCC中的一個錯誤。

根據[dcl.spec.auto] / 1:

autodecltype(auto) 類型指定器用於指定占位符類型,稍后將通過從初始化程序中進行推導來替換該占位符類型。 [...]

模板參數推導的規則永遠不會將類型推斷為auto 在這種情況下,扣除的目的實際上是用推導類型替換 auto

在示例中, list具有依賴類型(它取決於模板參數ListItem ),因此表達式list->size() - 1也具有依賴類型,這使得i的類型也依賴,這意味着它只會在實例化函數模板printList解析。 只有這樣才能檢查與該聲明相關的其他語義約束。

根據[temp.res] / 8:

知道哪些名稱是類型名稱允許檢查每個模板的語法。 如果出現以下情況,該計划格式錯誤,無需診斷:

[......這里沒有適用的案例清單......]

否則, 不能為可以生成有效特化的模板發出診斷 [ 注意:如果實例化模板,將根據本標准中的其他規則診斷錯誤。 確切地說,這些錯誤被診斷出來是一個實施質量問題。 - 結束說明 ]

(強調我的)

在分析模板printList的定義時,GCC發出錯誤是錯誤的,因為可以生成明確有效的模板特化。 實際上,如果QList沒有size()返回除int之外的任何特殊化,則ij的聲明在printList所有實例化中都是有效的。


所有引用均來自N4606 ,(幾乎)當前的工作草案,但上面引用的相關部分自C ++ 14以來沒有改變。


更新:在GCC 6/7中確認為回歸 。感謝TC提供錯誤報告。

更新:原始錯誤( 78693 )已修復即將發布的6.4和7.0版本。 它還揭示了GCC處理此類構造的方式的其他一些問題,導致另外兩個錯誤報告: 7900979013

正如我對你的回答的評論所述,我同意你所提出的分析。
最簡單的問題形式( 演示 ):

template<class T>
void foo (T t) {
  auto i = t, j = 1; // error: inconsistent deduction for ‘auto’: ‘auto’ and then ‘int’
}    
int main () {}

對於模板,編譯器在其第一階段,檢查基本語法而不實例化它。 在我們的例子中,我們永遠不會調用foo()

現在,在上面的例子中, idecltype(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

然后,當ij具有不同類型時,編譯器會正確報告錯誤及其層次結構。

然后,我將收到有關該主題的信息。

示例代碼中的問題在於使用模板函數。 編譯器做了模板的通用首先檢查沒有實例它,這意味着類型是模板參數(以及依賴於它們,就像其他模板類型)不知道,和auto ,如果它依賴於那些未知類型推導成再次auto (或不推斷為某種具體類型)。 它從來沒有在我看來即使扣除后auto仍然可以auto 現在原始的編譯器錯誤文本很有意義:變量j推導為int類型,但變量i在推導后仍然是auto 由於autoint是不同的類型,編譯器會生成錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM