为什么我会收到 Wsign 转换警告?

Igo*_*gor 5 c++ gcc type-conversion implicit-conversion c++11

我有以下代码:

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
}
Run Code Online (Sandbox Code Playgroud)

当我在 gcc 上编译它(在 7.3.0 和 8.2.0 上测试)时,-Wsign-conversion我收到“警告:从‘long unsigned int’转换为‘long int’可能会改变结果的符号”。如果y有 type long unsigned int,则没有警告。此外,当我明确调用时y.get()也没有警告:

std::cout << (x + y.get()); // this is ok
Run Code Online (Sandbox Code Playgroud)

为什么会出现这种情况呢?使用用户定义的转换时,是否有一些不能使用的指针算术特殊规则?

ein*_*ica 2

似乎是编译器问题/错误

(感谢@liliscent纠正我之前所说的话)

首先,让我们为您提到的所有声明制作一个最小的可重现示例:

#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';
}
Run Code Online (Sandbox Code Playgroud)

使用 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
Run Code Online (Sandbox Code Playgroud)

在链接中,您将看到如何:

  • GCC 在所有(最新)版本中都会发出此错误。
  • Clang 在 6.0 版本中发出此错误。
  • Clang在 7.0 版本中不会发出此错误

因此,这肯定是一些关于标准合规性的极端情况。

...但不要进入“Here Be Dragons”领域。

现在,我确信有一个复杂的技术解释说明了为什么您只在这些流语句的第三个上收到错误。但我认为从实际使用的角度来看这并不重要。如果您坚持只向指针添加正确的整数 - 就像您对.get()语句所做的那样 - 您不会收到该警告。

您看,您正在尝试将用户定义的类型添加到指针 - 这通常没有多大意义。确实,您的结构可以转换为整数,但是依赖于隐式进行的这种转换会让您面临诸如选择转换其他操作数或您未考虑的其他转换路径之类的事情。更重要的是,在这些情况下,您可能会“遇到”标准中有关隐式转换何时合法的一些深奥条款,编译器可能会或可能不会完全正确地实现这些条款(请参阅@cppcleaner的评论)。

因此,只需在您的代码中使用x + y3.get(),您就不必担心这些深奥的极端情况。

我在这个答案中就使用空字符串的索引 0 提出了类似的论点(是的,就是这样)。

  • 恐怕这并不能回答所发布的问题。我完全理解这是答案的第二部分,第一部分将解释原因。这样答案就会变成“这就是原因;但请做一些理智的事情,就像这样。” 但如果没有第一部分,这就不是答案。了解某件事发生的原因可能比“因为它确实有效而有效的解决方案”更有价值。 (2认同)