If statement failing to evaluate condition
Asked Answered
U

1

1

I have a basic class that containers two enumerators, one for input and one for output. It has two member functions which are both static. The first function is just a static function that returns a value based on the input. It will call the second function which is a constexpr function template that will return the constexpr values. You can see the full class here.

class Foo {
public:
    enum Input {
        INPUT_0 = 0,
        INPUT_1,
        INPUT_2
    };

    enum Output {
        OUTPUT_0 = 123,
        OUTPUT_1 = 234,
        OUTPUT_2 = 345
    };

    static uint16_t update( uint8_t input ) {
        if ( static_cast<int>(input) == INPUT_0 )
            return updater<INPUT_0>();
        if ( static_cast<int>(input) == INPUT_1 )
            return updater<INPUT_1>();
        if ( static_cast<int>(input) == INPUT_2 )
            return updater<INPUT_2>();

        return updater<INPUT_0>();
    }

    template<const uint8_t In>
    static constexpr uint16_t updater() {

        if constexpr( In == INPUT_0 ) {
            std::cout << "Output updated to: " << OUTPUT_0 << '\n';
            return OUTPUT_0;
        }

        if constexpr( In == INPUT_1 ) {
            std::cout << "Output updated to: " << OUTPUT_1 << '\n';
            return OUTPUT_1;
        }

        if constexpr( In == INPUT_2 ) {
            std::cout << "Output updated to: " << OUTPUT_2 << '\n';
            return OUTPUT_2;
        }
    }
};

If I use the function template itself as such when the values are known at compile time:

#include <iostream>

int main() {
    auto output0 = Foo::updater<Foo::INPUT_0>();
    auto output1 = Foo::updater<Foo::INPUT_1>();
    auto output2 = Foo::updater<Foo::INPUT_2>();

    std::cout << "\n--------------------------------\n";
    std::cout << "Output0: " << output0 << '\n'
              << "Output1: " << output1 << '\n'
              << "Output2: " << output2 << '\n';    

    return 0;
}

I am getting the correct output:

-Output-

Output updated to: 123
Output updated to: 234
Output updated to: 345

---------------------------------
Output0: 123
Output1: 234
Output2: 345

However when I try to use the non constexpr member function when the values are determined at runtime, for some reason or another the non constexpr function is failing to execute the code within the if statements.

#include <iostream>

int main() {
    uint8_t input;
    std::cout << "Please enter input value [0,2]\n";
    std::cin >> input;

    auto output = Foo::update( input );

    std::cout << "Output: " << output << '\n';

    return 0;        
}

Regardless of what value I enter from the keyboard, 0, 1 or 2, it is failing to execute the code within Foo::update()'s if statements. It is always printing out a value of 123.

If it helps; I'm using Visual Studio 2017 CE v15.9.4 and I'm compiling it with language set to ISO C++ Latest Draft Standard (/std:c++latest).

I don't know why this code is failing to evaluate the if statements to true and calling the code within their scope.

Uis answered 11/1, 2019 at 23:27 Comment(0)
A
3

input is receiving a char, so it will be set to the ASCII value of the inputted character. E.g. entering 2 will set input to 50.

Next time, use a debugger to identify where your program logic goes astray. You could have easily found the solution to your problem on your own.

Amorphous answered 11/1, 2019 at 23:33 Comment(6)
Okay, but why does it work when they are compile time constants but not when runtime?Uis
Because Foo:INPUT0, Foo:INPUT1, and Foo:INPUT2 are equal to 0, 1, and 2 respectively. The issue is with the std::cin, which receives chars. A char with a value of '1' will have the value of 49, for example.Amorphous
The cast is to int is useless because it just uses the underlying ASCII value of the character. You should use input - '0' to get the correct value.Amorphous
Okay, so instead of casting input to int, should I cast INPUT_X to char?Uis
@FrancisCugler Converting a char to an integer would cause the same problem, because 0 converted to a char yields \0 ie the null terminator.Amorphous
I got it now; it's been a while since I've worked with basic chars and ascii, it's taking me back 15+ years when I was learning C which I rarely use anymore.Uis

© 2022 - 2024 — McMap. All rights reserved.