我有以下代码:
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
为什么会这样?是否存在一些特殊的指针算术规则,这些规则在使用用户定义的转换时无法使用?
答案 0 :(得分:1)
(感谢@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,我们get:
<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
在链接上,您将看到如何:
所以一定是一些特殊情况符合标准。
现在,我敢肯定有一个复杂的技术解释,说明为什么您仅在这些流式处理语句的第3条上出现错误。但我认为从实际使用的角度来看,这并不重要。如果您坚持只向指针添加适当的整数(如使用.get()
语句一样),则不会收到该警告。
您看到的,您正在尝试将用户定义的类型添加到指针中-通常这没有多大意义。的确可以将结构转换为整数,但是依靠这种隐式转换 可以使您进行选择转换其他操作数或未考虑的其他转换路径的操作。此外,在某些情况下,您可能会“敲定”标准中有关隐式转换何时合法的某些深奥条款,编译器可能会或不会完全正确地实现隐式转换(请参阅@cppcleaner的注释)。
因此,只需在代码中使用x + y3.get()
,就不必担心这些神秘的极端情况。
我在this answer中做了类似的论点,涉及空字符串的索引0的使用(是的,就是这样)。