Can a C++ macro count the cases in a switch statement? - c++

I have many different lambdas that all iterate through a list of parameters and pick some of them (with a switch) to do an operation on. I want to make sure that each lambda finds at least one of each case it is looking for and to report back if any case isn't hit. I can setup a vector of bools to track if each case was found, but I need to know the full count of cases in the switch to see if I got them all and to see the indices of the bools. I'd really like to integrate it in the general case macro, that way nothing will break if a case gets added later without updating a count.
Lambda example:
#define OneCase ???
auto MysteryLambda = [](Parameters params) -> int
{
//something to set the case count to 0, whatever it is
for (auto param : params)
{
switch (param)
{
case First:
OneCase; //case count + 1
//do operation
break;
case Second:
OneCase; //case count + 1
//do operation
break;
case Third:
OneCase; //case count + 1
//do operation
break;
}
}
static const int cases = ???; //this would be 3
std::cout << "The enum has " << cases << " cases." << std::endl;
return cases;
};
Then the lambda can return that const count. Is this possible?
If it isn't possible, is there an alternative way to do this?

It would be just this side of possible to use the GCC/MSVC __COUNTER__ macro for this, though it would entail a significant amount of scaffolding around the switch statement itself. In general, no, it's not possible. It sounds like you want a map of lambdas, not a switch statement.

Ok, Sneftel's __COUNTER__ suggestion is viable! Here's how I managed to make it work:
enum class Parameter //sample parameters, they don't have to be the same for each lambda
{
First, Second, Third, Fourth
};
typedef std::vector<Parameter> Parameters;
void test()
{
static const int startcases = __COUNTER__ + 1; //the initial state of counter when this lambda is pre-proced
auto GetIndex = [](unsigned int counter) -> unsigned int //helper function, it takes __COUNTER__ from wherever it is called
{
return counter - startcases;
};
//Example lambda. This isn't built to do anything useful at all.
auto Example = [&GetIndex](Parameters parameters, std::vector<bool>& used) -> unsigned int
{
for (auto parameter : parameters)
{
switch (parameter) //only looking at First and Third
{
case Parameter::First:
used[GetIndex(__COUNTER__)] = true;
break;
case Parameter::Third:
used[GetIndex(__COUNTER__)] = true;
break;
}
}
static const unsigned int cases = __COUNTER__ - startcases; //this would be 2
std::cout << "The enum has " << cases << " cases." << std::endl;
return cases;
};
//Ok, time for a test!
//Load out sample params, using VC++2012 so no init list on vectors. :(
Parameters parameters;
parameters.push_back(Parameter::First);
parameters.push_back(Parameter::Second);
parameters.push_back(Parameter::First); //no Third in this vector
parameters.push_back(Parameter::Fourth);
std::vector<bool> used; //a vector of bools filled to some arbitrary capacity with falses, I can have size checks in a more extensive helper function so no big deal
used.insert(used.begin(), 10, false);
unsigned int cases = Example(parameters, used); //returns # of cases in this particular lambda
for (unsigned int i = 0; i < cases; ++i) //loop through for each case and see if one is false (meaning it had no hit)
{
if (!used[i])
{
std::cerr << "Didn't process case " << i << "." << std::endl;
}
}
}
Output:
The enum has 2 cases.
Didn't process case 1.

Idea: Turn a switch into a bunch of if statements that record their presence in an array.
Preamble:
#define BIG_ENOUGH 50 // Just needs to be bigger than the maximum enum value
#define BEGIN_DETECTED_SWITCH(x) \
{ \
vector<bool> __has(BIG_ENOUGH, false); \
vector<bool> __saw(BIG_ENOUGH, false); \
auto __x(x); \
{ ; // Dummy open brace to be consumed by first DETECTED_CASE()
#define END_DETECTED_SWITCH \
} \
for (int i = 0; i < BIG_ENOUGH; ++i) { \
if (__has[i] && !__saw[i]) { \
cout << "Didn't see any " << i << "'s!\n"; \
} \
} \
}
#define DETECTED_CASE(x) \
} \
__has[x] = true; \
if (__x == (x)) { \
__saw[x] = true;
Now turn each switch statement into:
BEGIN_DETECTED_SWITCH(someEnumVal)
DETECTED_CASE(First)
// Code for first
DETECTED_CASE(Second)
// Code for second
DETECTED_CASE(Third)
// Code for Third
END_DETECTED_SWITCH
You could slightly generalise it by having END_DETECTED_SWITCH take a lambda parameter that gets called with every non-firing case, instead of hardcoding the "reaction".

If the number of lines of code per case is fixed (admittedly a hard constraint), the answer is yes !
Insert Begin= __LINE__; before the switch and End= __LINE__; after it. Anytime later, (End - Begin - Extra) / LinesPerCase gives you the answer :)

Related

Is there a way to replace two similar functions that is different only by type by a single solution in this case?

There's an class named PlotCurve. It describes a chart as a container of points and operations on them. A data for PlotCurve is gotten from the class RVDataProvider. Important thing is that the amount of points that is provided by RVDataProvider may be big (more than 1kk) so RVDataProvider returns a read-only pointer to Y data (X data can be calculated by index of the pointer) to improve the perfomance.
The main problem is that RVDataProvider has two different methods for two types:
class RVDataProvider : public QObject, public IRVImmutableProvider
{
public:
// ...
ReadonlyPointer<float> getSignalDataFloat(int signalIndex, quint64 start, quint64 count) override;
ReadonlyPointer<double> getSignalDataDouble(int signalIndex, quint64 start, quint64 count) override;
// ...
}
ReadonlyPointer<T> is only a read-only wrapper of a C-style pointer.
In order to get a curve's range of values (for looking for min-max, painting them on the canvas, etc) I am supposed to declare different functions too.
class PlotCurve : public QObject
{
public:
// ...`
virtual ReadonlyPointer<float> getFloatPointer(quint64 begin, quint64 length) const;
virtual ReadonlyPointer<double> getDoublePointer(quint64 begin, quint64 length) const;
// ...
}
It leads to using switch statement in the client code and its changes if the new available type of data is added.
switch (dataType())
{
case RVSignalInfo::DataType::Float: {
auto pointer = getFloatPointer(begin, length);
Q_ASSERT(!(pointer).isNull()); \
for (quint64 i = 0; i < (length); ++i) { \
auto y = (pointer)[i]; \
if (y < (minY)) { (minY) = y; continue; } \
if (y > (maxY)) { (maxY) = y; } \
}
} break;
case RVSignalInfo::DataType::Double: {
auto pointer = getDoublePointer(begin, length);
Q_ASSERT(!(pointer).isNull()); \
for (quint64 i = 0; i < (length); ++i) { \
auto y = (pointer)[i]; \
if (y < (minY)) { (minY) = y; continue; } \
if (y > (maxY)) { (maxY) = y; } \
}
} break;
// ...
}
Is there a way to get rid of dependencies to a client code? Three thing came to my mind:
1) Create Iterator type that would be a wrapper of ReadonlyPointer. Nope - performance is decreased to 10+ times because of iterator's virtual functions.
2) Create a traverse method that would be perform some function to every value in some range. Nope again - the most optimized version using function pointers is two times slower than switch statement in client code.
3) Make the class PlotCurve template. In this way I can't add different PlotCurves to the one container like it is now.
Unfortunately, I don't see much which can be done for OPs problem.
At best, the similar looking parts of cases could be moved to
a macro
a function template
to prevent code duplication.
For demonstration, I resembled OPs problem with the following sample code:
enum DataType { Float, Double };
struct Data {
std::vector<float> dataFloat;
std::vector<double> dataDouble;
DataType type;
Data(const std::vector<float> &data): dataFloat(data), type(Float) { }
Data(const std::vector<double> &data): dataDouble(data), type(Double) { }
};
With a function template, processing could look like this:
namespace {
// helper function template for process()
template <typename T>
std::pair<double, double> getMinMax(const std::vector<T> &values)
{
assert(values.size());
double min = values[0], max = values[0];
for (const T &value : values) {
if (min > value) min = value;
else if (max < value) max = value;
}
return std::make_pair(min, max);
}
} // namespace
void process(const Data &data)
{
std::pair<double, double> minMax;
switch (data.type) {
case Float: minMax = getMinMax(data.dataFloat); break;
case Double: minMax = getMinMax(data.dataDouble); break;
}
std::cout << "range: " << minMax.first << ", " << minMax.second << '\n';
}
Live Demo on coliru
With a macro it would appear even more compact:
void process(const Data &data)
{
std::pair<double, double> minMax;
switch (data.type) {
#define CASE(TYPE) \
case TYPE: { \
assert(data.data##TYPE.size()); \
minMax.first = minMax.second = data.data##TYPE[0]; \
for (const double value : data.data##TYPE) { \
if (minMax.first > value) minMax.first = value; \
else if (minMax.second < value) minMax.second = value; \
} \
} break
CASE(Float);
CASE(Double);
#undef CASE
}
std::cout << "range: " << minMax.first << ", " << minMax.second << '\n';
}
Live Demo on coliru
Many people (me included) consider macros in C++ as dangerous. In opposition to everything else, macros are not subject of namespaces or scopes. This can cause confusion if any identifier becomes unexpectedly subject of preprocessing. In worst case, the unintendedly modified code passes compiler and leads to unexpected behavior in runtime. (My sad experience.)
However, this is not expected in this case (assuming the code would be part of a source file).
I would've preferred a third alternative which places the repeated code inside of process(). A lambda came in my mind but lambdas can not (yet) be templated: SO: Can lambda functions be templated?.
A local template (functor) isn't alternative. It's prohibited as well: SO: Why can't templates be declared in a function?.
After feedback of OP, a note about X macros: It's an ancient technique in C to prevent redundancy of data.
A "data table" is defined where each row is a "call" of a (here not defined) macro X which contains all features.
To use the data table:
define a macro X which uses just the arguments which are needed in the individual case (and ignores the rest)
#include the data table
#undef X.
The sample again:
void process(const Data &data)
{
std::pair<double, double> minMax;
switch (data.type) {
#define X(TYPE_ID, TYPE) \
case TYPE_ID: { \
assert(data.data##TYPE_ID.size()); \
minMax.first = minMax.second = data.data##TYPE_ID[0]; \
for (const double value : data.data##TYPE_ID) { \
if (minMax.first > value) minMax.first = value; \
else if (minMax.second < value) minMax.second = value; \
} \
} break;
#include "Data.inc"
#undef X
}
std::cout << "range: " << minMax.first << ", " << minMax.second << '\n';
}
where Data.inc is:
X(Float, float)
X(Double, double)
X(Int, int)
Live Demon on coliru
Although, this macro-trickery makes a bit scary – this is very convenient concerning maintenance. If a new data type has to be added, a new X() line in Data.inc (and, of course, a re-compile) is all what's necessary. (The compiler / build chain will hopefully consider all dependencies of sources from Data.inc. We never faced problems with this in Visual Studio.)

Make compiler assume that all cases are handled in switch without default

Let's start with some code. This is an extremely simplified version of my program.
#include <stdint.h>
volatile uint16_t dummyColorRecepient;
void updateColor(const uint8_t iteration)
{
uint16_t colorData;
switch(iteration)
{
case 0:
colorData = 123;
break;
case 1:
colorData = 234;
break;
case 2:
colorData = 345;
break;
}
dummyColorRecepient = colorData;
}
// dummy main function
int main()
{
uint8_t iteration = 0;
while (true)
{
updateColor(iteration);
if (++iteration == 3)
iteration = 0;
}
}
The program compiles with a warning:
./test.cpp: In function ‘void updateColor(uint8_t)’:
./test.cpp:20:25: warning: ‘colorData’ may be used uninitialized in this function [-Wmaybe-uninitialized]
dummyColorRecepient = colorData;
~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
As you can see, there is an absolute certainty that the variable iteration is always 0, 1 or 2. However, the compiler doesn't know that and it assumes that switch may not initialize colorData. (Any amount of static analysis during compilation won't help here because the real program is spread over multiple files.)
Of course I could just add a default statement, like default: colorData = 0; but this adds additional 24 bytes to the program. This is a program for a microcontroller and I have very strict limits for its size.
I would like to inform the compiler that this switch is guaranteed to cover all possible values of iteration.
As you can see, there is an absolute certainty that the variable iteration is always 0, 1 or 2.
From the perspective of the toolchain, this is not true. You can call this function from someplace else, even from another translation unit. The only place that your constraint is enforced is in main, and even there it's done in a such a way that might be difficult for the compiler to reason about.
For our purposes, though, let's take as read that you're not going to link any other translation units, and that we want to tell the toolchain about that. Well, fortunately, we can!
If you don't mind being unportable, then there's GCC's __builtin_unreachable built-in to inform it that the default case is not expected to be reached, and should be considered unreachable. My GCC is smart enough to know that this means colorData is never going to be left uninitialised unless all bets are off anyway.
#include <stdint.h>
volatile uint16_t dummyColorRecepient;
void updateColor(const uint8_t iteration)
{
uint16_t colorData;
switch(iteration)
{
case 0:
colorData = 123;
break;
case 1:
colorData = 234;
break;
case 2:
colorData = 345;
break;
// Comment out this default case to get the warnings back!
default:
__builtin_unreachable();
}
dummyColorRecepient = colorData;
}
// dummy main function
int main()
{
uint8_t iteration = 0;
while (true)
{
updateColor(iteration);
if (++iteration == 3)
iteration = 0;
}
}
(live demo)
This won't add an actual default branch, because there's no "code" inside it. In fact, when I plugged this into Godbolt using x86_64 GCC with -O2, the program was smaller with this addition than without it — logically, you've just added a major optimisation hint.
There's actually a proposal to make this a standard attribute in C++ so it could be an even more attractive solution in the future.
Use the "immediately invoked lambda expression" idiom and an assert:
void updateColor(const uint8_t iteration)
{
const auto colorData = [&]() -> uint16_t
{
switch(iteration)
{
case 0: return 123;
case 1: return 234;
}
assert(iteration == 2);
return 345;
}();
dummyColorRecepient = colorData;
}
The lambda expression allows you to mark colorData as const. const variables must always be initialized.
The combination of assert + return statements allows you to avoid warnings and handle all possible cases.
assert doesn't get compiled in release mode, preventing overhead.
You can also factor out the function:
uint16_t getColorData(const uint8_t iteration)
{
switch(iteration)
{
case 0: return 123;
case 1: return 234;
}
assert(iteration == 2);
return 345;
}
void updateColor(const uint8_t iteration)
{
const uint16_t colorData = getColorData(iteration);
dummyColorRecepient = colorData;
}
You can get this to compile without warnings simply by adding a default label to one of the cases:
switch(iteration)
{
case 0:
colorData = 123;
break;
case 1:
colorData = 234;
break;
case 2: default:
colorData = 345;
break;
}
Alternatively:
uint16_t colorData = 345;
switch(iteration)
{
case 0:
colorData = 123;
break;
case 1:
colorData = 234;
break;
}
Try both, and use the shorter of the two.
I know there have been some good solutions, but alternatively If your values are going to be known at compile time, instead of a switch statement you can use constexpr with a static function template and a couple of enumerators; it would look something like this within a single class:
#include <iostream>
class ColorInfo {
public:
enum ColorRecipient {
CR_0 = 0,
CR_1,
CR_2
};
enum ColorType {
CT_0 = 123,
CT_1 = 234,
CT_2 = 345
};
template<const uint8_t Iter>
static constexpr uint16_t updateColor() {
if constexpr (Iter == CR_0) {
std::cout << "ColorData updated to: " << CT_0 << '\n';
return CT_0;
}
if constexpr (Iter == CR_1) {
std::cout << "ColorData updated to: " << CT_1 << '\n';
return CT_1;
}
if constexpr (Iter == CR_2) {
std::cout << "ColorData updated to: " << CT_2 << '\n';
return CT_2;
}
}
};
int main() {
const uint16_t colorRecipient0 = ColorInfo::updateColor<ColorInfo::CR_0>();
const uint16_t colorRecipient1 = ColorInfo::updateColor<ColorInfo::CR_1>();
const uint16_t colorRecipient2 = ColorInfo::updateColor<ColorInfo::CR_2>();
std::cout << "\n--------------------------------\n";
std::cout << "Recipient0: " << colorRecipient0 << '\n'
<< "Recipient1: " << colorRecipient1 << '\n'
<< "Recipient2: " << colorRecipient2 << '\n';
return 0;
}
The cout statements within the if constexpr are only added for testing purposes, but this should illustrate another possible way to do this without having to use a switch statement provided your values will be known at compile time. If these values are generated at runtime I'm not completely sure if there is a way to use constexpr to achieve this type of code structure, but if there is I'd appreciate it if someone else with a little more experience could elaborate on how this could be done with constexpr using runtime values. However, this code is very readable as there are no magic numbers and the code is quite expressive.
-Update-
After reading more about constexpr it has come to my attention that they can be used to generate compile time constants. I also learned that they can not generate runtime constants but they can be used within a runtime function. We can take the above class structure and use it within a runtime function as such by adding this static function to the class:
static uint16_t colorUpdater(const uint8_t input) {
// Don't forget to offset input due to std::cin with ASCII value.
if ( (input - '0') == CR_0)
return updateColor<CR_0>();
if ( (input - '0') == CR_1)
return updateColor<CR_1>();
if ( (input - '0') == CR_2)
return updateColor<CR_2>();
return updateColor<CR_2>(); // Return the default type
}
However I want to change the naming conventions of the two functions. The first function I will name colorUpdater() and this new function that I just shown above I will name it updateColor() as it seems more intuitive this way. So the updated class will now look like this:
class ColorInfo {
public:
enum ColorRecipient {
CR_0 = 0,
CR_1,
CR_2
};
enum ColorType {
CT_0 = 123,
CT_1 = 234,
CT_2 = 345
};
static uint16_t updateColor(uint8_t input) {
if ( (input - '0') == CR_0 ) {
return colorUpdater<CR_0>();
}
if ( (input - '0') == CR_1 ) {
return colorUpdater<CR_1>();
}
if ( (input - '0') == CR_2 ) {
return colorUpdater<CR_2>();
}
return colorUpdater<CR_0>(); // Return the default type
}
template<const uint8_t Iter>
static constexpr uint16_t colorUpdater() {
if constexpr (Iter == CR_0) {
std::cout << "ColorData updated to: " << CT_0 << '\n';
return CT_0;
}
if constexpr (Iter == CR_1) {
std::cout << "ColorData updated to: " << CT_1 << '\n';
return CT_1;
}
if constexpr (Iter == CR_2) {
std::cout << "ColorData updated to: " << CT_2 << '\n';
return CT_2;
}
}
};
If you want to use this with compile time constants only you can use it just as before but with the function's updated name.
#include <iostream>
int main() {
auto output0 = ColorInfo::colorUpdater<ColorInfo::CR_0>();
auto output1 = ColorInfo::colorUpdater<ColorInfo::CR_1>();
auto output2 = ColorInfo::colorUpdater<ColorInfo::CR_2>();
std::cout << "\n--------------------------------\n";
std::cout << "Recipient0: " << output0 << '\n'
<< "Recipient1: " << output1 << '\n'
<< "Recipient2: " << output2 << '\n';
return 0;
}
And if you want to use this mechanism with runtime values you can simply do the following:
int main() {
uint8_t input;
std::cout << "Please enter input value [0,2]\n";
std::cin >> input;
auto output = ColorInfo::updateColor(input);
std::cout << "Output: " << output << '\n';
return 0;
}
And this will work with runtime values.
Well, if you are sure you won't have to handle other possible values, you can just use arithmetic. Gets rid of he branching and the load.
void updateColor(const uint8_t iteration)
{
dummyColorRecepient = 123 + 111 * iteration;
}
I'm going to extend the Lightness Races in Orbit's answer.
The code I'm using currently is:
#ifdef __GNUC__
__builtin_unreachable();
#else
__assume(false);
#endif
__builtin_unreachable() works in GCC and Clang but not MSVC. I used __GNUC__ to check whether it is one of the first two (or another compatible compiler) and used __assume(false) for MSVC instead.

Switch statement of ranges

Is there a way to write a switch statement in c++ where you deal with ranges.
case 0-10 do a,
case 20-40 do b,
case 40-80 do c,
etc.
I can write it out using a bunch of if else if statements but wondering if there is a more efficient way.
Actually, you can do this through preprocessor abuse in C (although perhaps not in C++, due to some errors with P99 in C++, which I am confident could be overcome with enough perseverance).
See the following example, using P99:
#include "p99.h"
#define P99_SWITCH_RANGE(from, to) P99_FOR(from, P99_MINUS(to, from), P99_SWITCH_RANGE_GLUE_HELPER, P99_SWITCH_RANGE_CASE_LABEL_MAKER_HELPER)
#define P99_SWITCH_RANGE_GLUE_HELPER(from, i, past, cur) past: cur
#define P99_SWITCH_RANGE_CASE_LABEL_MAKER_HELPER(from, x, i) case P99_ADD(from, i)
int main(int argc, const char *argv[]) {
int x;
scanf("%i", &x);
switch (x) {
P99_SWITCH_RANGE(20, 30):
{
puts("between 20 and 30");
}
default: {
puts("not between 20 and 30");
}
}
}
Note that this example is left inclusive, right exclusive. I'm confident you could modify the macros to make it any way you'd like, so this is a decent starting point at the very least.
I can write it out using a bunch of if else if statements but wondering if there is a more efficient way.
No. There's not a more efficient way. Not to mention that the switch statement is really not supposed to be used for ranges.
You could use a map mapping keys to standard functions:
#include <iostream>
#include <map>
#include <functional>
using namespace std;
int main()
{
std::map<int, std::function<void()>> dispatcher;
// case (-inf, 10]
dispatcher[10] = []() {cout << 10;};
// case (10, 50]
dispatcher[50] = []() {cout << 50;};
// case (50, 100]
dispatcher[100] = []() {cout << 100;};
(dispatcher.lower_bound(1)->second)();
(dispatcher.lower_bound(10)->second)();
(dispatcher.lower_bound(11)->second)();
(dispatcher.lower_bound(50)->second)();
(dispatcher.lower_bound(51)->second)();
return 0;
}
Outputs 10105050100
If you are concerned about efficiency, you could map the ranges to values and then switch for them:
int range_to_value(int x)
{
if (x > 0 && x < 10) return 0;
if (x > 20 && x < 40) return 1;
// ...
}
void switch_range(int x)
{
switch( range_to_value(x) )
{
case 0: cout << 0; break;
case 1: cout << 1; break;
}
}
switch_range(1); // output 0
switch_range(9); // output 0
switch_range(22); // output 1
Range mapping is probably inlined, but will be computed every time. Most efficient will be large switch, doesn't matter how you write it (by hand, generator, preprocessor) because it will end up as a large jump table.
try this:
case 0 ... 10:
case 20 ... 40:
case 41 ... 80:
etc..

Using a function call in a case statement label

Can you have a function call as a case statement label. For instance:
char x
switch(x)
{
case isCapital():
capitalcount++;
break;
case isVowel():
vowelcount++;
break;
.
.
.
.
.
}
Is this permitted within C++?
The value in a case label needs to be a constant expression. That is, the answer to your immediate question is: yes, you can call certain functions in a case label. However, not the ones you tried to call. You can have multiple labels refer to one group of statements, though:
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
do_vowels();
break;
I know this doesn't answer your question per se, but you might try coding it like this....
capitalcount += isCapital(x);
vowelcount += isVowel(x);
The boolean return type of the isXXX() functions would get promoted to an int and added to the counts as either 0 (false) or 1 (true).
First of all: in your desired code isCapital and isVowel should be not functions (and not a function call, definitely), but functors -- because to check a value they have to receive it via parameters...
anyway your code is not possible in C++... but can be simulated with a sequence of pairs of functions: predicate + effect. Predicate have to take some parameter and respond with a boolean. Effect will do smth if predicate is true. To simulate break and fallback to next case (i.e. when no break in a case) effect function also have to return a boolean.
Sample code may look like this:
#include <cctype>
#include <functional>
#include <iostream>
#include <vector>
int main(int argc, char* argv[])
{
typedef std::vector<
std::pair<
std::function<bool(char)> // predicate
, std::function<bool()> // effect: return true if `break' required
>
> case_seq_t;
unsigned digits = 0;
unsigned upper = 0;
unsigned lower = 0;
unsigned total = 0;
unsigned other = 0;
case_seq_t switch_seq = {
{
// predicate lambda can be replaced by std::bind
// in this simple case... but need to change param type.
// std::bind(&std::isdigit, std::placeholders::_1)
[](char c) { return std::isdigit(c); }
, [&]() { digits++; return true; }
}
, {
[](char c) { return std::islower(c); }
, [&]() { lower++; return true; }
}
, {
[](char c) { return std::isupper(c); }
, [&]() { upper++; return true; }
}
// `default` case
, {
[](char c) { return true; }
, [&]() { other++; return true; }
}
};
for (int i = 1; i < argc; i++)
for (int pos = 0; argv[i][pos]; pos++)
for (const auto& p : switch_seq)
if (p.first(argv[i][pos]))
if (p.second())
break;
std::cout << "digits=" << digits << std::endl;
std::cout << "upper=" << upper << std::endl;
std::cout << "lower=" << lower << std::endl;
std::cout << "other=" << other << std::endl;
return 0;
}
Not so simple as switch but (IMHO) obvious enough... and maybe, in some real cases, have better flexibility (and probably maintainability) :)

Why can't the switch statement be applied to strings?

Compiling the following code gives the error message: type illegal.
int main()
{
// Compilation error - switch expression of type illegal
switch(std::string("raj"))
{
case"sda":
}
}
You cannot use string in either switch or case. Why? Is there any solution that works nicely to support logic similar to switch on strings?
The reason why has to do with the type system. C/C++ doesn't really support strings as a type. It does support the idea of a constant char array but it doesn't really fully understand the notion of a string.
In order to generate the code for a switch statement the compiler must understand what it means for two values to be equal. For items like ints and enums, this is a trivial bit comparison. But how should the compiler compare 2 string values? Case sensitive, insensitive, culture aware, etc ... Without a full awareness of a string this cannot be accurately answered.
Additionally, C/C++ switch statements are typically generated as branch tables. It's not nearly as easy to generate a branch table for a string style switch.
As mentioned previously, compilers like to build lookup tables that optimize switch statements to near O(1) timing whenever possible. Combine this with the fact that the C++ Language doesn't have a string type - std::string is part of the Standard Library which is not part of the Language per se.
I will offer an alternative that you might want to consider, I've used it in the past to good effect. Instead of switching over the string itself, switch over the result of a hash function that uses the string as input. Your code will be almost as clear as switching over the string if you are using a predetermined set of strings:
enum string_code {
eFred,
eBarney,
eWilma,
eBetty,
...
};
string_code hashit (std::string const& inString) {
if (inString == "Fred") return eFred;
if (inString == "Barney") return eBarney;
...
}
void foo() {
switch (hashit(stringValue)) {
case eFred:
...
case eBarney:
...
}
}
There are a bunch of obvious optimizations that pretty much follow what the C compiler would do with a switch statement... funny how that happens.
C++
constexpr hash function:
constexpr unsigned int hash(const char *s, int off = 0) {
return !s[off] ? 5381 : (hash(s, off+1)*33) ^ s[off];
}
switch( hash(str) ){
case hash("one") : // do something
case hash("two") : // do something
}
Update:
The example above is C++11. There constexpr function must be with single statement. This was relaxed in next C++ versions.
In C++14 and C++17 you can use following hash function:
constexpr uint32_t hash(const char* data, size_t const size) noexcept{
uint32_t hash = 5381;
for(const char *c = data; c < data + size; ++c)
hash = ((hash << 5) + hash) + (unsigned char) *c;
return hash;
}
Also C++17 have std::string_view, so you can use it instead of const char *.
In C++20, you can try using consteval.
C++ 11 update of apparently not #MarmouCorp above but http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4067/Switch-on-Strings-in-C.htm
Uses two maps to convert between the strings and the class enum (better than plain enum because its values are scoped inside it, and reverse lookup for nice error messages).
The use of static in the codeguru code is possible with compiler support for initializer lists which means VS 2013 plus. gcc 4.8.1 was ok with it, not sure how much farther back it would be compatible.
/// <summary>
/// Enum for String values we want to switch on
/// </summary>
enum class TestType
{
SetType,
GetType
};
/// <summary>
/// Map from strings to enum values
/// </summary>
std::map<std::string, TestType> MnCTest::s_mapStringToTestType =
{
{ "setType", TestType::SetType },
{ "getType", TestType::GetType }
};
/// <summary>
/// Map from enum values to strings
/// </summary>
std::map<TestType, std::string> MnCTest::s_mapTestTypeToString
{
{TestType::SetType, "setType"},
{TestType::GetType, "getType"},
};
...
std::string someString = "setType";
TestType testType = s_mapStringToTestType[someString];
switch (testType)
{
case TestType::SetType:
break;
case TestType::GetType:
break;
default:
LogError("Unknown TestType ", s_mapTestTypeToString[testType]);
}
The problem is that for reasons of optimization the switch statement in C++ does not work on anything but primitive types, and you can only compare them with compile time constants.
Presumably the reason for the restriction is that the compiler is able to apply some form of optimization compiling the code down to one cmp instruction and a goto where the address is computed based on the value of the argument at runtime. Since branching and and loops don't play nicely with modern CPUs, this can be an important optimization.
To go around this, I am afraid you will have to resort to if statements.
std::map + C++11 lambdas pattern without enums
unordered_map for the potential amortized O(1): What is the best way to use a HashMap in C++?
#include <functional>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
int main() {
int result;
const std::unordered_map<std::string,std::function<void()>> m{
{"one", [&](){ result = 1; }},
{"two", [&](){ result = 2; }},
{"three", [&](){ result = 3; }},
};
const auto end = m.end();
std::vector<std::string> strings{"one", "two", "three", "foobar"};
for (const auto& s : strings) {
auto it = m.find(s);
if (it != end) {
it->second();
} else {
result = -1;
}
std::cout << s << " " << result << std::endl;
}
}
Output:
one 1
two 2
three 3
foobar -1
Usage inside methods with static
To use this pattern efficiently inside classes, initialize the lambda map statically, or else you pay O(n) every time to build it from scratch.
Here we can get away with the {} initialization of a static method variable: Static variables in class methods , but we could also use the methods described at: static constructors in C++? I need to initialize private static objects
It was necessary to transform the lambda context capture [&] into an argument, or that would have been undefined: const static auto lambda used with capture by reference
Example that produces the same output as above:
#include <functional>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
class RangeSwitch {
public:
void method(std::string key, int &result) {
static const std::unordered_map<std::string,std::function<void(int&)>> m{
{"one", [](int& result){ result = 1; }},
{"two", [](int& result){ result = 2; }},
{"three", [](int& result){ result = 3; }},
};
static const auto end = m.end();
auto it = m.find(key);
if (it != end) {
it->second(result);
} else {
result = -1;
}
}
};
int main() {
RangeSwitch rangeSwitch;
int result;
std::vector<std::string> strings{"one", "two", "three", "foobar"};
for (const auto& s : strings) {
rangeSwitch.method(s, result);
std::cout << s << " " << result << std::endl;
}
}
To add a variation using the simplest container possible (no need for an ordered map)... I wouldn't bother with an enum--just put the container definition immediately before the switch so it'll be easy to see which number represents which case.
This does a hashed lookup in the unordered_map and uses the associated int to drive the switch statement. Should be quite fast. Note that at is used instead of [], as I've made that container const. Using [] can be dangerous--if the string isn't in the map, you'll create a new mapping and may end up with undefined results or a continuously growing map.
Note that the at() function will throw an exception if the string isn't in the map. So you may want to test first using count().
const static std::unordered_map<std::string,int> string_to_case{
{"raj",1},
{"ben",2}
};
switch(string_to_case.at("raj")) {
case 1: // this is the "raj" case
break;
case 2: // this is the "ben" case
break;
}
The version with a test for an undefined string follows:
const static std::unordered_map<std::string,int> string_to_case{
{"raj",1},
{"ben",2}
};
// in C++20, you can replace .count with .contains
switch(string_to_case.count("raj") ? string_to_case.at("raj") : 0) {
case 1: // this is the "raj" case
break;
case 2: // this is the "ben" case
break;
case 0: //this is for the undefined case
}
In C++ and C switches only work on integer types. Use an if else ladder instead. C++ could obviously have implemented some sort of swich statement for strings - I guess nobody thought it worthwhile, and I agree with them.
Why not? You can use switch implementation with equivalent syntax and same semantics.
The C language does not have objects and strings objects at all, but
strings in C is null terminated strings referenced by pointer.
The C++ language have possibility to make overload functions for
objects comparision or checking objects equalities.
As C as C++ is enough flexible to have such switch for strings for C
language and for objects of any type that support comparaison or check
equality for C++ language. And modern C++11 allow to have this switch
implementation enough effective.
Your code will be like this:
std::string name = "Alice";
std::string gender = "boy";
std::string role;
SWITCH(name)
CASE("Alice") FALL
CASE("Carol") gender = "girl"; FALL
CASE("Bob") FALL
CASE("Dave") role = "participant"; BREAK
CASE("Mallory") FALL
CASE("Trudy") role = "attacker"; BREAK
CASE("Peggy") gender = "girl"; FALL
CASE("Victor") role = "verifier"; BREAK
DEFAULT role = "other";
END
// the role will be: "participant"
// the gender will be: "girl"
It is possible to use more complicated types for example std::pairs or any structs or classes that support equality operations (or comarisions for quick mode).
Features
any type of data which support comparisions or checking equality
possibility to build cascading nested switch statemens.
possibility to break or fall through case statements
possibility to use non constatnt case expressions
possible to enable quick static/dynamic mode with tree searching (for C++11)
Sintax differences with language switch is
uppercase keywords
need parentheses for CASE statement
semicolon ';' at end of statements is not allowed
colon ':' at CASE statement is not allowed
need one of BREAK or FALL keyword at end of CASE statement
For C++97 language used linear search.
For C++11 and more modern possible to use quick mode wuth tree search where return statement in CASE becoming not allowed.
The C language implementation exists where char* type and zero-terminated string comparisions is used.
Read more about this switch implementation.
I think the reason is that in C strings are not primitive types, as tomjen said, think in a string as a char array, so you can not do things like:
switch (char[]) { // ...
switch (int[]) { // ...
In c++ strings are not first class citizens. The string operations are done through standard library. I think, that is the reason. Also, C++ uses branch table optimization to optimize the switch case statements. Have a look at the link.
http://en.wikipedia.org/wiki/Switch_statement
Late to the party, here's a solution I came up with some time ago, which completely abides to the requested syntax.
#include <uberswitch/uberswitch.hpp>
int main()
{
uswitch (std::string("raj"))
{
ucase ("sda"): /* ... */ break; //notice the parenthesis around the value.
}
}
Here's the code: https://github.com/falemagn/uberswitch
You could put the strings in an array and use a constexpr to convert them to indices at compile time.
constexpr const char* arr[] = { "bar", "foo" };
constexpr int index(const char* str) { /*...*/ }
do_something(std::string str)
{
switch(quick_index(str))
{
case index("bar"):
// ...
break;
case index("foo"):
// ...
break;
case -1:
default:
// ...
break;
}
For quick_index, which doesn't have to be constexpr, you could e.g. use an unordered_map to do it O(1) at runtime. (Or sort the array and use binary search, see here for an example.)
Here's a full example for C++11, with a simple custom constexpr string comparer. Duplicate cases and cases not in the array (index gives -1) will be detected at compile time. Missing cases are obviously not detected. Later C++ versions have more flexible constexpr expressions, allowing for simpler code.
#include <iostream>
#include <algorithm>
#include <unordered_map>
constexpr const char* arr[] = { "bar", "foo", "foobar" };
constexpr int cmp(const char* str1, const char* str2)
{
return *str1 == *str2 && (!*str1 || cmp(str1+1, str2+1));
}
constexpr int index(const char* str, int pos=0)
{
return pos == sizeof(arr)/sizeof(arr[0]) ? -1 : cmp(str, arr[pos]) ? pos : index(str,pos+1);
}
int main()
{
// initialize hash table once
std::unordered_map<std::string,int> lookup;
int i = 0;
for(auto s : arr) lookup[s] = i++;
auto quick_index = [&](std::string& s)
{ auto it = lookup.find(s); return it == lookup.end() ? -1 : it->second; };
// usage in code
std::string str = "bar";
switch(quick_index(str))
{
case index("bar"):
std::cout << "bartender" << std::endl;
break;
case index("foo"):
std::cout << "fighter" << std::endl;
break;
case index("foobar"):
std::cout << "fighter bartender" << std::endl;
break;
case -1:
default:
std::cout << "moo" << std::endl;
break;
}
}
hare's comment to Nick's solution is really cool. here the complete code example (in C++11):
constexpr uint32_t hash(const std::string& s) noexcept
{
uint32_t hash = 5381;
for (const auto& c : s)
hash = ((hash << 5) + hash) + (unsigned char)c;
return hash;
}
constexpr inline uint32_t operator"" _(char const* p, size_t) { return hash(p); }
std::string s = "raj";
switch (hash(s)) {
case "sda"_:
// do_something();
break;
default:
break;
}
In C++ you can only use a switch statement on int and char
cout << "\nEnter word to select your choice\n";
cout << "ex to exit program (0)\n";
cout << "m to set month(1)\n";
cout << "y to set year(2)\n";
cout << "rm to return the month(4)\n";
cout << "ry to return year(5)\n";
cout << "pc to print the calendar for a month(6)\n";
cout << "fdc to print the first day of the month(1)\n";
cin >> c;
cout << endl;
a = c.compare("ex") ?c.compare("m") ?c.compare("y") ? c.compare("rm")?c.compare("ry") ? c.compare("pc") ? c.compare("fdc") ? 7 : 6 : 5 : 4 : 3 : 2 : 1 : 0;
switch (a)
{
case 0:
return 1;
case 1: ///m
{
cout << "enter month\n";
cin >> c;
cout << endl;
myCalendar.setMonth(c);
break;
}
case 2:
cout << "Enter year(yyyy)\n";
cin >> y;
cout << endl;
myCalendar.setYear(y);
break;
case 3:
myCalendar.getMonth();
break;
case 4:
myCalendar.getYear();
case 5:
cout << "Enter month and year\n";
cin >> c >> y;
cout << endl;
myCalendar.almanaq(c,y);
break;
case 6:
break;
}
More functional workaround to the switch problem:
class APIHandlerImpl
{
// define map of "cases"
std::map<string, std::function<void(server*, websocketpp::connection_hdl, string)>> in_events;
public:
APIHandlerImpl()
{
// bind handler method in constructor
in_events["/hello"] = std::bind(&APIHandlerImpl::handleHello, this, _1, _2, _3);
in_events["/bye"] = std::bind(&APIHandlerImpl::handleBye, this, _1, _2, _3);
}
void onEvent(string event = "/hello", string data = "{}")
{
// execute event based on incomming event
in_events[event](s, hdl, data);
}
void APIHandlerImpl::handleHello(server* s, websocketpp::connection_hdl hdl, string data)
{
// ...
}
void APIHandlerImpl::handleBye(server* s, websocketpp::connection_hdl hdl, string data)
{
// ...
}
}
You can use switch on strings.
What you need is table of strings, check every string
char** strings[4] = {"Banana", "Watermelon", "Apple", "Orange"};
unsigned get_case_string(char* str, char** _strings, unsigned n)
{
while(n)
{
n--
if(strcmp(str, _strings[n]) == 0) return n;
}
return 0;
}
unsigned index = get_case_string("Banana", strings, 4);
switch(index)
{
case 1: break;/*Found string `Banana`*/
default: /*No string*/
}
You can't use string in switch case.Only int & char are allowed. Instead you can try enum for representing the string and use it in the switch case block like
enum MyString(raj,taj,aaj);
Use it int the swich case statement.
That's because C++ turns switches into jump tables. It performs a trivial operation on the input data and jumps to the proper address without comparing. Since a string is not a number, but an array of numbers, C++ cannot create a jump table from it.
movf INDEX,W ; move the index value into the W (working) register from memory
addwf PCL,F ; add it to the program counter. each PIC instruction is one byte
; so there is no need to perform any multiplication.
; Most architectures will transform the index in some way before
; adding it to the program counter
table ; the branch table begins here with this label
goto index_zero ; each of these goto instructions is an unconditional branch
goto index_one ; of code
goto index_two
goto index_three
index_zero
; code is added here to perform whatever action is required when INDEX = zero
return
index_one
...
(code from wikipedia https://en.wikipedia.org/wiki/Branch_table)
in many cases you can avid extra work by pulling the first char from the string and switching on that. may end up having to do a nested switch on charat(1) if your cases start with the same value. anyone reading your code would appreciate a hint though because most would prob just if-else-if
Switches only work with integral types (int, char, bool, etc.). Why not use a map to pair a string with a number and then use that number with the switch?