簡體   English   中英

為什么會收到Wsign轉換警告?

[英]Why do I get Wsign-conversion warning?

我有以下代碼:

template <typename T>
struct wrapper {
    T t;
    operator T() { return t; }
    T get() { return t; }
};

int main() {
    int a[10];
    int* x = a;
    wrapper<long unsigned int> y{2};
    std::cout << (x + y); // warning
}

當我使用-Wsign-conversion在gcc上編譯(在7.3.0和8.2.0上測試)時,我得到“警告:從'long unsigned int'轉換為'long int'可能會改變結果的符號”。 如果y具有long unsigned int類型,則沒有警告。 而且,當我顯式調用y.get() ,也沒有警告:

std::cout << (x + y.get()); // this is ok

為什么會這樣呢? 是否存在一些特殊的指針算術規則,這些規則在使用用戶定義的轉換時無法使用?

似乎是編譯器問題/錯誤

(感謝@liliscent糾正了我之前在這里所說的內容)

首先,讓我們為您提到的所有語句制作一個MCVE

#include <iostream>

template <typename T>
struct wrapper {
    T t;
    operator T() const { return t; }
    T get() const { return t; }
};

int main() {
    int a[10];
    int* x { a } ;
    wrapper<long int> y1{2};
    wrapper<unsigned int> y2{2};
    wrapper<long unsigned int> y3{2};

    std::cout << (x + y1) << '\n';
    std::cout << (x + y2) << '\n';
    std::cout << (x + y3) << '\n'; // this triggers a warning
    std::cout << (x + y3.get()) << '\n';
}

並使用GCC 8.2.0,我們得到

<source>: In function 'int main()':
<source>:20:23: warning: conversion to 'long int' from 'long unsigned int' may change the sign of the result [-Wsign-conversion]
     std::cout << (x + y3) << '\n';
                       ^~
Compiler returned: 0

在該鏈接上,您將看到如何:

  • GCC在所有(最新)版本中均會發出此錯誤。
  • Clang在版本6.0中發出此錯誤。
  • Clang在7.0版中不會發出此錯誤。

因此必須符合標准。

...但是不要進入“這里就是龍”的領域。

現在,我敢肯定有一個復雜的技術解釋,說明為什么在這些流式語句的第3條上只會出現錯誤。 但我認為從實際使用的角度來看這並不重要 如果您堅持只向指針添加適當的整數(如使用.get()語句一樣.get() ,則不會收到該警告。

您會看到,您正在嘗試將用戶定義的類型添加到指針中-通常這沒有多大意義。 確實可以將結構轉換為整數,但是依靠隱式進行此轉換會使您面臨選擇轉換其他操作數或未考慮的其他轉換路徑的麻煩。 更重要的是,在這些情況下,您可能會在標准中“打”一些深奧的條款,涉及何時隱式轉換是合法的,編譯器可能會或可能不會以完全正確的方式實現(見@cppcleaner的注釋)。

因此,只需在代碼中使用x + y3.get() ,您就不必擔心這些神秘的x + y3.get()情況。

我在此答案中使用了類似的參數,關於空字符串的索引0的使用(是的,就是這樣)。

暫無
暫無

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

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