2

I have a function test, which prints out the underlying type of an enum parameter:

enum class TestEnum : uint32_t
{

};

template<typename TEnum>
    void test(TEnum v)
{ // Line 12
    if constexpr (std::is_same_v<std::underlying_type_t<TEnum>,int8_t>)
        std::cout<<"int8"<<std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>,uint8_t>)
        std::cout<<"uint8"<<std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>,int16_t>)
        std::cout<<"int16"<<std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>,uint16_t>)
        std::cout<<"uint16"<<std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>,int32_t>)
        std::cout<<"int32"<<std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>,uint32_t>)
        std::cout<<"uint32"<<std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>,int64_t>)
        std::cout<<"int64"<<std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>,uint64_t>)
        std::cout<<"uint64"<<std::endl;
    else
        static_assert(false,"Unsupported enum type!");
}

int main(int argc,char *argv[])
{
    TestEnum e {};
    test<TestEnum>(e);
    return EXIT_SUCCESS;
}

The program compiles and runs fine in Visual Studio 2017 (with ISO C++17), however the last else is underlined in red with the following message:

expected a statement

detected during instantiation of "void test(TEnum v) [with TEnum=TestEnum]" at line 12

Program code with last 'else' underlined in red.

(I've tried using else constexpr instead of just else, but that doesn't seem to matter.)

If I remove the last else if-branch (the one checking for uint64_t), the error disappears:

Program code without the last 'else if'-branch, and no error message.

Is this a bug in Visual Studio, or am I doing something that I shouldn't?

Community
  • 1
  • 1
Silverlan
  • 2,783
  • 3
  • 31
  • 66
  • 1
    Not sure if related, but `static_assert(false, ...);` will always fire, even if the branch isn't taken. To prevent that, the expression has to depend on a template parameter. Something like `!sizeof(TEnum)` will suffice. – HolyBlackCat Sep 08 '18 at 14:56
  • It doesn't always fire though, it only fires if I use a type that isn't covered by one of the if-branches, just as intended. Is this non-standard behavior? – Silverlan Sep 08 '18 at 15:01
  • I am a fool. Sorry for the edit spam. The IDE must be pretty confused if the editor shows errors, but the compiler accepts it just fine. – melpomene Sep 08 '18 at 15:12
  • Does the error disappear if you remove any of the other `else if` branches or if you add another `if` condition? – melpomene Sep 08 '18 at 15:14
  • 2
    @Silverlan After looking it up, I'm not sure. It [does fire](http://coliru.stacked-crooked.com/a/d8c7b0240670bd63) on GCC. This post says it makes the program ill-formed, no diagnostic required: https://stackoverflow.com/questions/38304847/constexpr-if-and-static-assert Also, reading it again, it seems that even `!sizeof(TEnum)` doesn't prevent the program from being ill-formed... – HolyBlackCat Sep 08 '18 at 15:15
  • @HolyBlackCat You're looking for `static_assert(always_false);` – Passer By Sep 08 '18 at 15:33
  • @PasserBy That is, something like `template inline constexpr bool always_false = 0;`? – HolyBlackCat Sep 08 '18 at 15:46
  • Yeah. The theory being technically there could be some hypothetical specialization somewhere down the line that evaluates to `true`. – Passer By Sep 08 '18 at 16:38
  • I have paste your code with a version preview 15.8 preview2,0 and the warning does not fire. Sure you selected std:c++latest ? – PilouPili Sep 08 '18 at 16:41
  • @NPE You have to make sure 'TestEnum' was specified as Template Instantiation type. (Via the ""-Icon when you have the template function selected.) – Silverlan Sep 08 '18 at 17:16

2 Answers2

1

I am sure this is not actually the answer you expected but… this code

enum class TestEnum : uint32_t
{

};

template<typename TEnum>
void test(TEnum v)
{ // Line 12
    if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, int8_t>)
    {
        std::cout << "int8" << std::endl;
    }
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, uint8_t>)
    {
        std::cout << "uint8" << std::endl;
    }
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, int16_t>)
    {
        std::cout << "int16" << std::endl;
    }
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, uint16_t>)
    {
        std::cout << "uint16" << std::endl;
    }
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, int32_t>)
    {
        std::cout << "int32" << std::endl;
    }
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, uint32_t>)
    {
        std::cout << "uint32" << std::endl;
    }
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, int64_t>)
    {
        std::cout << "int64" << std::endl;
    }
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, uint64_t>)
    {
        std::cout << "uint64" << std::endl;
    }
    else
    {
        static_assert(false, "Unsupported enum type!");
    }
}

int main(int argc, char *argv[])
{
    TestEnum e{};
    test<TestEnum>(e);
    return EXIT_SUCCESS;
} 

does not produce any warning

enter image description here

however

enum class TestEnum : uint32_t
{

};

template<typename TEnum>
void test(TEnum v)
{ // Line 12
    if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, int8_t>)
        std::cout << "int8" << std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, uint8_t>)
        std::cout << "uint8" << std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, int16_t>)
        std::cout << "int16" << std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, uint16_t>)
        std::cout << "uint16" << std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, int32_t>)
        std::cout << "int32" << std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, uint32_t>)
        std::cout << "uint32" << std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, int64_t>)
        std::cout << "int64" << std::endl;
    else if constexpr (std::is_same_v<std::underlying_type_t<TEnum>, uint64_t>)
        std::cout << "uint64" << std::endl;
    else
        static_assert(false, "Unsupported enum type!");
}

int main(int argc, char *argv[])
{
    TestEnum e{};
    test<TestEnum>(e);
    return EXIT_SUCCESS;
}

produces the same message as in your first screen capture. I know it's french but trust me it says the same.

enter image description here

Just for the debate I never really understood why the norm still allows

if(boolean) do;

while

if(boolean) { do;}

does the job and with no ambiguity whatsoever. Surely a dirty heritage of what Fortran 77 allowed. Frankly 40 years has past and we are not about to scream if we have to add two more characters... Well I am not...

PilouPili
  • 2,601
  • 2
  • 17
  • 31
0

it seems to be a bug in IntelliSense. It's not related with uint64_t or any other type. Everything above 8 if/else branches start to produce this error. Feel free to report to Microsoft

Andriy Tylychko
  • 15,967
  • 6
  • 64
  • 112