Reputation: 10314
I am getting a 'case expression not constant' error in a switch statement. However, the header provides a definition for the used constants, and the constructor provides initialisation for them in its initialization list.
Additionally, when I mouse over the "problem" statements it identifies them as constants.
const int ThisClass::EXAMPLE_CONSTANT
error expression must have a constant value
This seems a little counter-intuitive to me. I did some research and found a similar problem that someone else had. They were told that all constants must in fact be initialised in 'main' and that this was a limitation of the language. Is this really the case? It seems unlikely.
Upvotes: 24
Views: 63538
Reputation: 383698
std::map
+ C++11 lambdas workaround
This method allows for non constants, should give us O(1)
amortized What is the best way to use a HashMap in C++? :
#include <ctime>
#include <functional>
#include <unordered_map>
#include <iostream>
int main() {
int result;
int key0 = std::time(NULL) % 3;
int key1 = (key0 + 1) % 3;
int key2 = (key0 + 2) % 3;
std::unordered_map<int,std::function<void()>> m{
{key0, [&](){ result = 0; }},
{key1, [&](){ result = 1; }},
{key2, [&](){ result = 2; }},
};
m[key0]();
std::cout << key0 << " " << result << std::endl;
m[key1]();
std::cout << key1 << " " << result << std::endl;
m[key2]();
std::cout << key2 << " " << result << std::endl;
}
Possible output:
1 0
2 1
0 2
For usage from inside a class, don't forget to build the map statically as shown at: Why switch statement cannot be applied on strings?
Upvotes: 1
Reputation: 39099
You need a "real" compile time integer constant. const
in C++ means read-only, and a const variable can
be initialized just like int y = 0; const int x = y;
, making x
a read-only copy of the value y
had at the time of initialization.
With a modern compiler, you can either use enum
s or constexpr
s to store (integral) members of compile-time-constness:
class Foo {
public:
static constexpr int x = 0;
enum { y = 1 };
};
int main () {
switch (0) {
case Foo::x: ;
case Foo::y: ;
}
}
Upvotes: 5
Reputation: 234584
This is a bit of a mess. In C++ const
can be used for several things, like declaring actual constants, and declaring read-only variables.
If you declare:
const int x = 0;
In global, namespace, or local scope, it is a constant. You can use it where constant expressions are required (like case labels or array sizes). However, at class scope or as a function parameter, it's just a read-only variable.
Additionally, if you declare at class scope:
static const int x = 0;
This is also a constant.
Upvotes: 2
Reputation: 320631
Constants used in case labels must be integral constant expressions. An integral constant expression must satisfy a much more strict set of requirements than just being an integral object declared as const
.
A non-static class member cannot be used in an integral constant expression, so what you are trying to do will not compile. A static class member, for example, can be used in an integral constant expression if its initializer is "visible" at the point of use.
Upvotes: 1
Reputation: 361612
The case
statements require integral value which must be known at compile-time, which is what is meant by constant here. But the const
members of a class are not really constant in that sense. They're are simply read-only.
Instead of fields, you can use enum
:
class ThisClass
{
public:
enum Constants
{
EXAMPLE_CONSTANT = 10,
ANOTHER_CONSTANT = 20
};
};
And then you can write,
switch(c)
{
case ThisClass::EXAMPLE_CONSTANT:
//code
break;
case ThisClass::ANOTHER_CONSTANT:
//code
break;
};
Upvotes: 22