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.

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59

1 Answers1

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.

Alessandro Power
  • 2,395
  • 2
  • 19
  • 39
  • Okay, but why does it work when they are compile time constants but not when runtime? – Francis Cugler Jan 11 '19 at 23:35
  • 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 `char`s. A `char` with a value of `'1'` will have the value of 49, for example. – Alessandro Power Jan 11 '19 at 23:37
  • 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. – Alessandro Power Jan 11 '19 at 23:39
  • Okay, so instead of casting `input` to `int`, should I cast `INPUT_X` to `char`? – Francis Cugler Jan 11 '19 at 23:39
  • @FrancisCugler Converting a char to an integer would cause the same problem, because `0` converted to a `char` yields `\0` ie the null terminator. – Alessandro Power Jan 11 '19 at 23:41
  • 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. – Francis Cugler Jan 11 '19 at 23:42