C/C++: switch for non-integers C/C++: switch for non-integers c c

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

NEWMATCHMATCH("asd")  some c++ codeMATCH("bqr")  ... the buffer for the match is in _bufMATCH("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.


In C++, you can obtain O(lg n) performance by having a std::map<std::string, functionPointerType>. (In C you could implement what was essentially the same but it would be more difficult) Pull out the right function pointer using std::map<k, v>::find, and call that pointer. Of course, that's not going to be nearly as simple as a language supported switch statement. On the other hand, if you have enough items that there's going to be a huge difference between O(n) and O(lg n), that's probably an indication that you should be going for a different design in the first place.

Personally, I've always found the ELSEIF chain more readable anyway.


You can achieve it without using any map or unordered_map like below.Compare first character alone to identify which string.If more than one match, then you can fallback to if/else chain within that case statement.Number of comparisons will be greatly reduced if not many strings starting with same letter.

char *str = "foo";switch(*str){case 'f':    //do something for foo    cout<<"Foo";    break;case 'b':    //do something for bar    break;case 'c':    if(strcmp(str, "cat") == 0)    {        //do something for cat    }    else if(strcmp(str, "camel") == 0)    {        //do something for camel    }}

This looks to be optimal solution without any cost, even though its not standard.