Seems like a compiler issue/bug
(thanks @liliscent for correcting what I said here earlier)
First, let's make a single minimal reproducible example for all of the statement you were mentioning:
#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';
}
and using GCC 8.2.0, we 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
at the link, you will see how:
- GCC emits this error with all (recent) versions.
- Clang emits this error with version 6.0.
- Clang does not emits this error with version 7.0.
So it must be some corner case w.r.t. standards compliance.
... but don't go into "Here Be Dragons" territory.
Now, I'm sure there's a complex technical explanation regarding why you only get an error on the 3rd of these streaming statements. But I claim it does not matter from a practical use perspective. If you stick to only adding proper integers to pointers - like you do with the .get()
statement - you wouldn't get that warning.
You see, you are trying to add up a user-defined type to a pointer - which doesn't make much sense generally. It's true that your structure can be converted into an integer, but relying on this conversion to be made implicitly opens you up to things like the choice to convert the other operand, or other conversion paths you have not considered. What's more, these are cases in which you might 'hit' some esoteric clause in the standard regarding when implicit conversions are legit, which may or may not be implemented with perfect correctness by the compiler (see @cppcleaner's comment).
So just use x + y3.get()
in your code and you'll not have to worry about these esoteric corner cases.
I have made a similar argument in this answer regarding the use of index 0 of an empty string (yes, that's a thing).