Writing "enum: int64_t" value to std::ostringstream truncates it to int - c++

This code behaves in an unexpected way with MSVC compiler (v141 toolset, /std:c++17):
#include <iostream>
#include <limits>
#include <sstream>
#include <stdint.h>
int main() {
std::ostringstream ss;
enum Enum : int64_t {muchos_digitos = std::numeric_limits<int64_t>::max() - 1000};
ss << muchos_digitos;
std::cout << ss.str();
return 0;
}
Specifically, it prints "-1001". It is only after much head scratching and enabling /W4 warning level that I discovered the cause:
warning C4305: 'argument': truncation from 'main::Enum' to 'int'
But why does it happen? Indeed, the debugger confirms that int overload is called instead of long long, but why? And how can I circumvent this in generic code? I could cast muchos_digitos to int64_t, but I receive the value as typename T. I can figure out that it's an enum, but how can I know that it's a strongly typed enum, and can I find out its underlying type? I don't think it's directly possible...
The output is correct under GCC, but I need the code to work with all three of GCC, clang and MSVC.
Online demo
P. S. It was a mistake that /W4 was not set for my project in the first place. I recommend everyone to use this level with MSVC and -pedantic-errors with GCC / clang, it really saves you time with bizzare errors and surprising behavior when you notice it at compile time as you write the code.

This was confirmed to be a bug by the Microsoft team and it's now fixed in VS 2019: https://developercommunity.visualstudio.com/content/problem/475488/wrong-ostringstreamoperator-overload-selected-for.html

Related

CppCoreChecker C-Style cast warning when using range based for loop on vector

Assume the following code:
#include <iostream>
#include <vector>
#include <string>
int main() {
std::vector<std::string> lines;
lines.push_back("line");
for (const auto& s : lines) {
std::cout << s;
}
}
At the line of the for loop I get the following warning:
C26493 Don't use C-style casts that would perform a static_cast downcast, const_cast, or reinterpret_cast.
Can someone explain where this is coming from? Im using Visual Studio 2017 Community Edition Version 15.2.
As seen in this bug report it seems to happen only for the std::string type when inserting into a basic_iostream. This bug has been resolved but hasn't been released yet so for now you'll just have to wait.

implict type conversion between int and string

How to prevent this implicit type conversion between int and std::string, which is very bug prone.
Here is the code.
#include <iostream>
#include <string>
using namespace std;
int main() {
string s="string";
s = 123456789; //assign a int value to std::string
cout << s;
// your code goes here
return 0;
}
The code above can be compiled with no warning, and the result is obvious not what the coder intended. Can this be avoided?
Update: 123456789 will cause overflow warning if -Wall flag is set. But if I changed into s = 98, there will be no warning anymore. but I actually want the string to be the string 98, not the ascii b character. How to prevent this then?
From what I understand, you'd want a warning if something like this occurred. For that, you should enable all warnings. Add the -Wall -Wextra flag while compiling.
However, you shouldn't need these flags in this particular case. If you haven't disabled warnings, you should get an implicit type conversion warning.
As mentioned in comments, to enable a warning specifically for this case, you could use the -Wconstant-conversion flag.

(Software issue) Can anyone suggest a download that will definitely bring my Mingw32 compiler up to speed?

#include <iostream>
#include <string>
using namespace std;
int main(){
string s = "wassup", newVal = "though";
cout << *(s.insert(s.begin(), newVal.begin(), newVal.end()));
}
This brings up the problem that the return type of string's insert member function is void (error: void value not ignored as it ought to be). This link indicates C++98 returns void but the "new" standard C++11 does indeed return an iterator.
A bit of context, I actually faced this problem earlier. I was/am using CodeBlocks (GCC Compiler Collection) on Windows 7 64-bit and this program gave the same issue (dereferencing void):
#include <iostream>
#include <list>
int main(){
list<int> x = {1,2,3,4};
*(x.insert(++x.begin(), 3, 2));
for(auto c : x)
cout << c;
}
I posted my issue on a different forum and a user pointed out Mingw32 was missing that particular C++11 change, indicating Mingw-w64 does not have this issue. So I went straight to installing Mingw-w64 on Code::Blocks using this guide and the problem was resolved. It's only now I've found out that the overloaded function which takes three iterator parameters STILL returns void.
I'm a little confused as to why Code::Blocks Mingw32 didn't supply a fully updated C++11 standard. Can anyone suggest a download that will definitely bring my compiler up to speed?

Why does abs(complex<int>) always return zero?

The following code with VS2010 prints 0, contrary to my expectations:
#include <complex>
#include <iostream>
using namespace std;
int main(void)
{
complex<int> z(20, 200);
cout << abs<int>(z) << endl;
return 0;
}
It works fine when the type is double.
According to the C++ ISO spec, ยง26.2/2:
The effect of instantiating the template complex for any type other than float, double or long double is unspecified.
In other words, the compiler can do whatever it wants to when you instantiate complex<int>. The fact that you're getting 0 here is perfectly well-defined behavior from a language perspective.
For a comparison - on ideone's version of gcc, this code doesn't even compile. That's another perfectly valid option.
Hope this helps!
On MinGW 4.6.2 it prints 200.
However, in the C++ ISO standard section 26.2.2:
The effect of instantiating the template complex for any type other than float, double or long double is unspecified.
So your build environment is exhibiting undefined behavior for complex<int>, which is not against the standard.
As templatetypedef pointed out, ideone's C99 compiler (GCC 4.3.4) refuses to compile it altogether.

C++ array Visual Studio 2010 vs Bloodshed Dev-C++ 4.9.9.2

This code compiles fine in Bloodshed Dev-C++ 4.9.9.2, but in Visual Studio 2010 I get an error: expression must have a constant value. How do I make an array after the user input about array size without using pointers?
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
int size = 1;
cout << "Input array size ";
cin >> size;
int array1[size];
system("PAUSE");
return 0;
}
Use an std::vector instead of an array (usually a good idea anyway):
std::vector<int> array1(size);
In case you care, the difference you're seeing isn't from Dev-C++ itself, it's from gcc/g++. What you're using is a non-standard extension to C++ that g++ happens to implement, but VC++ doesn't.
The ability to size automatic arrays using a variable is part of C, not part of C++, and is an extension that GCC seems to want to foist on us all. And DevC++ is an unholy piece of cr*p, although it is not at fault here. for a change (this is entirely GCC's doing) - I can't imagine why you (or anyone else) would want to use it.
You should really compile your C++ code with GCC with flags that warn you about stuff like this. I suggest -Wall and -pedantic as a minimum.
Or
int array1 = new int[size];
will work aswell I believe (been a month or 3 since I last touched C++)
But indeed, if using C++, go for an std::vector, much more flexible.