none
error C2440 type cast from double to int RRS feed

  • Question

  • Hello,

    what I am looking for is some expert advice on a question, and if possible a link to the C++ standard documentation (i.e. current standard, not vendor specific). I am using Visual Studio 2017 C++ to compile C++ for MATLAB (mex). MATLAB supports Visual Studio 2017, but seems to prefer MinGW, and my colleagues say that Visual Studio is "bad", and they only use MinGW. So, I want an expert opinion on the current question. One line of code causes error C2440, and I have written a test program to reproduce it.

    int main()
    {
    	double A = 1.1;
    	int B = 0;
    	enum firstType
    	{
    		type1 = 1,
    		type2 = 2
    	};
    	firstType  C = type2;
    	B = A; /* line 11, warning C4244 */
    	B = (int)A; /* OK */
    	C = (firstType)A; /* line 13, error C2440 */
    	C = (firstType)int(A); /* OK */
    	C = (firstType)static_cast<int>(A); /* OK */
    	C = static_cast<firstType>(A); /* line 16, error  C2440 */
    }

    Line 11 causes warning C4244

    Lines 13 and 16 cause error C2440

    Lines 14 and 15 are 2 ways to avoid the error in Visual Studio 2017.

    However, line 13 presumably works fine in MinGW.

    Why is line 13 flagged as an error in VS? Is there any "official" reason why it is wrong?


    Tom

    Tuesday, November 21, 2017 12:18 PM

Answers

  • Hello,

    in the past, the Standard allowed to cast a float to an enum: read this comment: https://stackoverflow.com/questions/14821846/c-casting-a-floating-point-value-to-an-enum-but-not-with-vs-2010

    Nowadays the Standard has changed. Only integral values (such as int) are allowed, no float: https://msdn.microsoft.com/en-us/library/c36yw7x9.aspx
    "The static_cast operator can explicitly convert an integral value to an enumeration type. If the value of the integral type does not fall within the range of enumeration values, the resulting enumeration value is undefined."

    http://en.cppreference.com/w/cpp/language/static_cast
    "8) A value of integer or enumeration type can be converted to any complete enumeration type. The result is unspecified (until C++17)undefined behavior (since C++17) if the value of expression is out of range (if the underlying type is fixed, the range is the range of the type. "

    enum values are always ints.
    By the way, what do you expect to be the result? Should the compiler cut the digits behind the point or round the floating value first (so is 1.8 1 or 2?)? So line 14 should be preferred.

    Regards, Guido





    • Edited by Guido Franzke Tuesday, November 21, 2017 2:35 PM
    • Marked as answer by TomLigon Tuesday, November 21, 2017 2:48 PM
    Tuesday, November 21, 2017 2:31 PM
  • On 11/21/2017 7:18 AM, TomLigon wrote:

    what I am looking for is some expert advice on a question, and if possible a link to the C++ standard documentation (i.e. current standard, not vendor specific). I am using Visual Studio 2017 C++ to compile C++ for MATLAB (mex). MATLAB supports Visual Studio 2017, but seems to prefer MinGW, and my colleagues say that Visual Studio is "bad", and they only use MinGW. So, I want an expert opinion on the current question. One line of code causes error C2440, and I have written a test program to reproduce it.

    [code]
    int main()
    {
      double A = 1.1;
      int B = 0;
      enum firstType
      {
        type1 = 1,
        type2 = 2
      };
      firstType  C = type2;
      B = A; * line 11, warning C4244 *

    This is just a warning. It tells you (correctly) that the conversion would lose information. As you've discovered, you can silence this warning with an explicit cast.

      B = (int)A; * OK *
      C = (firstType)A; * line 13, error C2440 *

    This looks like a bug to me. My reading of the standard is that this conversion should be allowed. GCC and clang compile this without issue.

    Relevant chapter and verse:

    [expr.cast]/4 The conversions performed by
    ...
    (4.2) — a static_cast (5.2.9)
    ...
    can be performed using the cast notation of explicit type conversion. The same semantic restrictions and behaviors apply...

    [expr.static.cast]/10 ... A value of floating-point type can also be explicitly converted to an enumeration type. The resulting value is the same as converting the original value to the underlying type of the enumeration (4.9), and subsequently to the enumeration type.

    So (firstType)A should compile, and behave the same as (firstType)(int)A, or equivalently static_cast<firstType>(static_cast<int>(A))

    • Marked as answer by TomLigon Tuesday, November 21, 2017 3:05 PM
    Tuesday, November 21, 2017 2:44 PM

All replies

  • Hello,

    in the past, the Standard allowed to cast a float to an enum: read this comment: https://stackoverflow.com/questions/14821846/c-casting-a-floating-point-value-to-an-enum-but-not-with-vs-2010

    Nowadays the Standard has changed. Only integral values (such as int) are allowed, no float: https://msdn.microsoft.com/en-us/library/c36yw7x9.aspx
    "The static_cast operator can explicitly convert an integral value to an enumeration type. If the value of the integral type does not fall within the range of enumeration values, the resulting enumeration value is undefined."

    http://en.cppreference.com/w/cpp/language/static_cast
    "8) A value of integer or enumeration type can be converted to any complete enumeration type. The result is unspecified (until C++17)undefined behavior (since C++17) if the value of expression is out of range (if the underlying type is fixed, the range is the range of the type. "

    enum values are always ints.
    By the way, what do you expect to be the result? Should the compiler cut the digits behind the point or round the floating value first (so is 1.8 1 or 2?)? So line 14 should be preferred.

    Regards, Guido





    • Edited by Guido Franzke Tuesday, November 21, 2017 2:35 PM
    • Marked as answer by TomLigon Tuesday, November 21, 2017 2:48 PM
    Tuesday, November 21, 2017 2:31 PM
  • On 11/21/2017 7:18 AM, TomLigon wrote:

    what I am looking for is some expert advice on a question, and if possible a link to the C++ standard documentation (i.e. current standard, not vendor specific). I am using Visual Studio 2017 C++ to compile C++ for MATLAB (mex). MATLAB supports Visual Studio 2017, but seems to prefer MinGW, and my colleagues say that Visual Studio is "bad", and they only use MinGW. So, I want an expert opinion on the current question. One line of code causes error C2440, and I have written a test program to reproduce it.

    [code]
    int main()
    {
      double A = 1.1;
      int B = 0;
      enum firstType
      {
        type1 = 1,
        type2 = 2
      };
      firstType  C = type2;
      B = A; * line 11, warning C4244 *

    This is just a warning. It tells you (correctly) that the conversion would lose information. As you've discovered, you can silence this warning with an explicit cast.

      B = (int)A; * OK *
      C = (firstType)A; * line 13, error C2440 *

    This looks like a bug to me. My reading of the standard is that this conversion should be allowed. GCC and clang compile this without issue.

    Relevant chapter and verse:

    [expr.cast]/4 The conversions performed by
    ...
    (4.2) — a static_cast (5.2.9)
    ...
    can be performed using the cast notation of explicit type conversion. The same semantic restrictions and behaviors apply...

    [expr.static.cast]/10 ... A value of floating-point type can also be explicitly converted to an enumeration type. The resulting value is the same as converting the original value to the underlying type of the enumeration (4.9), and subsequently to the enumeration type.

    So (firstType)A should compile, and behave the same as (firstType)(int)A, or equivalently static_cast<firstType>(static_cast<int>(A))

    • Marked as answer by TomLigon Tuesday, November 21, 2017 3:05 PM
    Tuesday, November 21, 2017 2:44 PM
  • Hello Guido,

    thanks for the reply! This is very much what I was looking for. Actually, I had already found the places you refer to, but I was unsure about what the "standard" really says, or even which version of which standard is relevant. 

    What do I expect? In my test program, "A" is simply defined as double, but in the real application, the double is being returned by a MATLAB routine mxGetScalar, which returns double. The expectation is that it will always return a number from the list that defines the enum, so no conversion is necessary. I haven't looked at all of the code, so it is conceivable that a user might supply an undefined value, in which the result would be undefined. My suggestion for avoiding the VS error message was in fact line 14, as you recommended.


    Tom

    Tuesday, November 21, 2017 2:59 PM
  • On 11/21/2017 9:31 AM, Guido Franzke wrote:

    in the past, the Standard allowed to cast a float to an enum: read this comment:https://stackoverflow.com/questions/14821846/c-casting-a-floating-point-value-to-an-enum-but-not-with-vs-2010

    Nowadays the Standard has changed. Only integral values (such as int) are allowed, no float:https://msdn.microsoft.com/en-us/library/c36yw7x9.aspx

    Where do you see this change in the standard? I see explicit wording to the contrary ( http://eel.is/c++draft/expr.static.cast#10 ):

    [expr.static.cast]/10 ... A value of floating-point type can also be explicitly converted to an enumeration type. The resulting value is the same as converting the original value to the underlying type of the enumeration (4.9), and subsequently to the enumeration type.

    http://en.cppreference.com/w/cpp/language/static_cast
    "8) A value of integer or enumeration type can be converted to any completeenumeration type <http://en.cppreference.com/w/cpp/language/enum>. The result is unspecified (until C++17)undefined behavior(since C++17) if the value of expression is out of range (if the underlying type is fixed, the range is the range of the type."

    If you read a bit further down, you'll find this sentence in the very same paragraph:
    "A value of a floating-point type can also be converted to any complete enumeration type"

    enum values are always ints.
    By the way, what do you expect to be the result? Should the compiler cut the digits behind the point or round the floating value first (so is 1.8 1 or 2?)?

    I expect the result to be the same as static_cast<firstType>(static_cast<int>(A)) , as prescribed by the standard.

    Tuesday, November 21, 2017 2:59 PM
  • Hello Igor,

    thanks, this is useful. Can you tell me where I can read the standard? If the error message is a bug in Visual Studio, I would like to report it, but it looks to me very much like it is intentional.


    Tom

    Tuesday, November 21, 2017 3:04 PM
  • On 11/21/2017 10:04 AM, TomLigon wrote:

    thanks, this is useful. Can you tell me where I can read the standard?

    http://en.cppreference.com/w/cpp/links
    There are links to final drafts of various standard versions (the actual official standard costs money, but final drafts have the exact same content).

    Also useful is http://eel.is/c++draft/  . This tracks the most recent draft (C++20 at the time of writing). Inconvenient for research (you cannot search the text there), but convenient in that you can get a direct link to a specific section or paragraph in the standard, for quoting in forums and such.

    Tuesday, November 21, 2017 3:18 PM

  • This is not quite true. In C++03, this conversion wasn't explicitly allowed, and this was recognized as issue 1094 [1] of the standard. All standards since C++11 [2, 3, 4, 5] include a second sentence that explicitly allows static_cast from floating-point types to enumeration types.  All compilers I checked (clang, gcc, icc) except MSVC implement this correctly.

    [1-5]: I would normally put references here, but MS won't let let me. I'm sorry, but you'll have to google it yourself.

    • Proposed as answer by Tobias.Hahn Thursday, October 24, 2019 4:33 PM
    Thursday, October 24, 2019 4:32 PM
  • The issue here isn't that it is implemented incorrectly, but in these two years nobody has reported it as a bug. The thing about Visual Studio is that it has a repot a problem button, so if something isn't working right then you can tell Microsoft about this.

    So if you want to state that Microsoft isn't implementing this correctly, do you want to report this as a bug so that Microsoft can fix it so it is implemented correctly?

    You marked yourself as a proposed answer, but wouldn't the real answer to this situation be to get Microsoft to fix the bug?


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Thursday, October 24, 2019 9:28 PM
  • Well, I did report this. You can find the bug report here.

    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Friday, October 25, 2019 2:10 AM
  • Thanks for reporting this! When I first posted the issue, I was using code written by someone else and shared on GitHub. Based on this input, the developer found a workaround and I was able to use the code as needed. Reporting and following up on bugs is always a good idea.

    Tom

    Friday, October 25, 2019 8:25 AM