C/C++: Switch For Non-Integers

C/C++: switch for non-integers

Using some nasty macro and template magic it's possible to get an unrolled binary search at compiletime with pretty syntax -- but the MATCHES ("case") have to be sorted: fastmatch.h

NEWMATCH
MATCH("asd")
some c++ code
MATCH("bqr")
... the buffer for the match is in _buf
MATCH("zzz")
... user.YOURSTUFF
/*ELSE
optional
*/
ENDMATCH(xy_match)

This will generate (roughly) a function bool xy_match(char *&_buf,T &user), so it must be at the outer level. Call it e.g. with:

xy_match("bqr",youruserdata);

And the breaks are implicit, you cannot fall-thru. It's also not heavily documented, sorry. But you'll find, that there are some more usage-possibilities, have a look. NOTE: Only tested with g++.

Update C++11:

Lambdas and initializer list make things much prettier (no macros involved!):

#include <utility>
#include <algorithm>
#include <initializer_list>

template <typename KeyType,typename FunPtrType,typename Comp>
void Switch(const KeyType &value,std::initializer_list<std::pair<const KeyType,FunPtrType>> sws,Comp comp) {
typedef std::pair<const KeyType &,FunPtrType> KVT;
auto cmp=[&comp](const KVT &a,const KVT &b){ return comp(a.first,b.first); };
auto val=KVT(value,FunPtrType());
auto r=std::lower_bound(sws.begin(),sws.end(),val,cmp);
if ( (r!=sws.end())&&(!cmp(val,*r)) ) {
r->second();
} // else: not found
}

#include <string.h>
#include <stdio.h>
int main()
{
Switch<const char *,void (*)()>("ger",{ // sorted:
{"asdf",[]{ printf("0\n"); }},
{"bde",[]{ printf("1\n"); }},
{"ger",[]{ printf("2\n"); }}
},[](const char *a,const char *b){ return strcmp(a,b)<0;});
return 0;
}

That's the idea. A more complete implementation can be found here: switch.hpp.

Update 2016: Compile time trie

My newest take on this problem uses advanced c++11 metaprogramming to
generate a search-trie at compile time.
Unlike the previous approaches, this will handle unsorted
case-branches/strings just fine; they only have to be string-literals.
G++ also allows constexpr for them, but not clang (as of HEAD 3.9.0 / trunk 274233).

In each trie node a switch-statement is utilized to harness the compiler's advanced code generator.

The full implementation is available at github: smilingthax/cttrie.

Why can't I use non-integral types with switch

The BCPL and C languages implemented switch (switchon in BCPL) as a higher-level implementation of an assembly branch table.

A branch table is a very efficient implementation of an if/else chain that uses a single integer to index into an array of addresses (or address offsets). Program control jumps to the address at the specified index of the table.

switch requires an integer type (or a type implicitly convertible to an integer) because array-indexing requires an integer type.

C++ inherited the same language properties of switch without making significant changes.

It would be possible to redefine the language to implement switch using operator ==, but that same behavior can already be implemented as an if/else chain.

switch quantity not an integer

I would like to point one flaw in your approach. You first compute all parts, and then map each part, whilst you could use an iterative approach to map each part as you discover it and thus need much less storage (and could loop indefinitely).

Because this seemed a fun problem, I decided to present here an alternative approach:

static std::map<std::string, char> const MorseMap = {
{".-", 'a'},
{"-...", 'b'},
...
};

void convert(std::istream& morse, std::ostream& regular) {
std::string buffer;
while (morse >> buffer) {
auto const it = MorseMap.find(buffer);
if (it == MorseMap.end()) { regular << '?'; continue; }

regular << it->second;
}
}

And yes, it works, and even remarks you have too many dashes as your fifth character.

In general, processing iteratively requires less memory, and yields more responsiveness, however it might complicate the design and slow down the overall computation; you have to judge whether it is worth it or not on a case by case basis.

Switch statement with integer value

You are switching on an int, which is correct, but your cases are not integers - they are char since they are surrounded in '.

'0' is never equal to 0, nor is '1' ever equal to 1.

Change the case values to integers.

int main()
{
int num1;

cout<< "enter either 0 or 1" << "\n";
cin>> num1;

switch (num1)
{
case 0:
cout<< "you entered 0" << endl << endl;
break;

case 1:
cout<< "you entered 1" << endl << endl;
break;

}

}

cpp - why you can't use boolean, float, & string in switch Statements

In days of old and sometimes today, switch statements were translated into arrays of branch or jump statements, preferably contiguous.

As with arrays, indices of 8.9, "frog", and "false" don't make sense.

The C and C++ languages are designed for efficiency when compiled. An array of jump instructions is much more efficient than having to do an "if-else-if" ladder, which is required for other index types (such as floating point and text or string).

For those pedantic readers:

Using integers as case values allows for better optimization (implementation) of the decision structure. Contiguous (consecutive) case values allow for better optimization or implementation. An optimal decision structure is an array of jump, branch instructions or pointers to functions.

For example, an optimum implementation would be:

destination_address = switch_table[case_value];
Many processors can implement this with a single instruction.

Other languages may implement a table of <case_value, destination_address>. One issue with floating point case values is that comparing for equality with floating point is difficult because not all numbers can be represented exactly by floating point. For example if you have case 3.14: and your index is 3.14159, is the case activated?

For string or text case-values, enough characters must be compared to determine equality. For example, "hyperbolic" and "hyperthreading" need to go through 5 iterations to determine equality. Hashing could be used, but there may be more execution with the hashing function than there are letters to compare.

So, to allow compact and efficient implementations of switch statements, the authors of the C and C++ language decided to restrict the case values to integers. Other forms, like strings, will require an if-else-if ladder, table search or dictionary (map).



Related Topics



Leave a reply



Submit