Search code examples
c++switch-statementconstantscompile-time-constant

Is there a way to define a switch-compliant constant for static object members?


I understand that I can't use the result of getValue() in a switch statement because the case tree is built at compile time.

What I have is a class which contains static const members that have a constant value set at runtime from a constructor. The value to be set is always known at compile time.

Is it possible to use templates or some other solution to define these const objects in a type safe manner and keep them as static members of a class?

Note that I do NOT want an enum in this case as I want to switch on different types such as an int in the following example.

Example:

#include <iostream>

using namespace std;

class Some_Class {
private:
   int _value;

public:
   Some_Class(int value) {
      _value = value;
   }

   int getValue() const {
      return _value;
   }

   static const Some_Class ONE;
   static const Some_Class TWO;
}; // class

const Some_Class Some_Class::ONE(1);
const Some_Class Some_Class::TWO(2);

int main() {
   int value = 1;

   switch (value) {
      case Some_Class::ONE.getValue():
         cout << "Do thing 1" << endl;
         break;
      case Some_Class::TWO.getValue():
         cout << "Do thing 2" << endl;
   }

   return 0;
}

This does not work for the aforementioned problem:

main.cpp(29) : error C2051: case expression not constant
main.cpp(32) : error C2051: case expression not constant

Solution

  • Something similar can be done, provided the constructor can be constexpr and the class can be inherited. Since we can't have static constexpr Some_Class as a member of Some_Class, we get around that with a derived class.

    #include <iostream>
    
    namespace detail
    {
        class Base_Class //Has the functionality
        {
        private:
            int _value;
        public:
            constexpr Base_Class(int value) : _value(value) {}
            constexpr int getValue() const
            {
                return _value;
            }
        };
    }
    
    //Inherits functionality, has static members
    class Some_Class : public detail::Base_Class
    {
    public:
        using Base_Class::Base_Class;
        static constexpr Base_Class ONE{1};
        static constexpr Base_Class TWO{2};
    };
    
    int main()
    {
        int value = 1;
        switch (value)
        {
        case Some_Class::ONE.getValue():
            std::cout << "Do thing 1" << std::endl;
            break;
        case Some_Class::TWO.getValue():
            std::cout << "Do thing 2" << std::endl;
        }
        return 0;
    }