2

currently I am doing the following:

enum TC_ID {
   CMD01 = 'C'*'M'*'D'*'0'*'1',
   CMD02 = 'C'*'M'*'D'*'0'*'2',
   ..
};

Which works, but is going to be quite effortfull for a whole lot of commands :D

So, I am looking for a Macro, or inline function or something else which multiplies all the chars of a char array/string with a fixed size, so that I don't have to type them in manually in my code.

Is something like this possible?


Some unnecessary but maybe interesting information:

Well, this looks kinda stupid, why am I doing this you might ask ;)

My goal is to use this enum in a switch statement, which in the end is used to execute telecommands for my project.

The size of my telecommands is always 5. So I am calculating some kind of very simple hash value which will be used inside the switch statement:

char *id // contains the Telecommand as a string
TC_ID hash = static_cast<TC_ID>(id[0]*id[1]*id[2]*id[3]*id[4]);

switch (hash) {
    case (CMD01):
        // execute funtion..
        break;
    case (CMD02):
        // do something else
        break;
    default:
        // unknown command
}

I know that instead of a switch I could just use a lot of if else statements and strcmp, but I don't want to because it's ugly :D

EDIT: Also, using an appropriate hash function would be much better.

However, how can this be implemented in an enumeration, so that I can still use my switch statement for the commands?

I think what I want is basically some kind of hash table which I can generate at the start for all command words and then make a switch over all of them.. but just how?

EDIT2: My compiler version is C++98

EDIT3: Workaround solution in comment in answer post

robo
  • 93
  • 7
  • 3
    This isn't a very good idea. What happens when you get to `CMD10` ? – M.M Dec 05 '15 at 23:01
  • 1
    @M.M Point taken. But it is not going to be very likely for my project, as I won't name them CMD01, CMD02 and so forth, rather something like: CH1DY - for setting Duty Cycle of PWM Channel 1 .. Anyway, using a proper a hash function would be more appropriate, I'm right there with you. But for my little project it should be fine. – robo Dec 05 '15 at 23:09
  • This is C++ code. I cannot think of an truly elegant way to do this in C. If you tag the question `C++` the experts in this other language might come up with something specific and appropriate. – chqrlie Dec 05 '15 at 23:33
  • Yes, sorry for that. It is c++ code. I messed up there! Changed now – robo Dec 05 '15 at 23:38
  • 1
    Does your compiler support C++11 or C++14? It's important, because with C++11 support you can use constexpr functions to do this, and with C++14 it's easier to write them. I've done this before to generate `case` values, but in my case I chose a hash function that was guaranteed to generate unique values, which doesn't seem to be the case here. – interjay Dec 05 '15 at 23:44
  • There's probably a better way to do this. – erip Dec 05 '15 at 23:44
  • 2
    `I think what I want is basically some kind of hash table` Why not use a hash table? – erip Dec 05 '15 at 23:52
  • I will look into this. Btw the compiler version being used for this project is: __cplusplus = 199711L, so C++98, right? – robo Dec 05 '15 at 23:58
  • C++98 isn't very well equipped for compile-time computation. – Petr Skocik Dec 06 '15 at 00:05
  • 1
    Looking at your actual problem, why do those enums members have to have explicit values. Just leave them implicit and you'll be guaranteed no conflicts. – Petr Skocik Dec 06 '15 at 00:17
  • 2
    C++98 compilers still exist? – M.M Dec 06 '15 at 01:04
  • @M.M unfortunately yes :D – robo Dec 06 '15 at 01:52
  • @robo Maybe yours can do both dialects, and you just need to tweak it. E.g., `g++` compiles in c++98 mode by default, in c++11 mode if you add `-std=c++11` or c++14 mode if you add `-std=c++1y`. – Petr Skocik Dec 06 '15 at 02:00

1 Answers1

2

This works (C++11):

constexpr int multChars(const char* s /*string*/, int t = 1 /*tally*/){
  return *s ? multChars(s+1, t*(*s)) : t;
};
//--------------------------------------------------------
//test it on a template (won't compile unless N is evaluated at compile time)
#include <iostream>    
template<int N>
void printN() { std::cout<<N<<'\n'; } 

int main(){
  printN<multChars("ab")>();
  return 0;
}

The ascii code of 'a' is 97 and the ascii code of 'b' is 98. This returns 9506 as expected.

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • Should probably use `unsigned long long` instead of int. – erip Dec 05 '15 at 23:53
  • 1
    Very elegant solution! Unfortunately I'm stuck with C++98 compiler for this project, so I can't use constexpr.. :/ – robo Dec 06 '15 at 00:07
  • Maybe have a script write that enum file for you, e.g., with bash code like this: `echo -n hello | while read -n 1 c; do echo -n "'$c'*"; done; echo 1` (prints `'h'*'e'*'l'*'l'*'o'*1`) – Petr Skocik Dec 06 '15 at 00:13
  • *elegant* does not exactly describe this, maybe magical or heroic? – chqrlie Dec 06 '15 at 00:28
  • @PSkocik I basically did what you said. I wrote a little programm which generates a hash code for my commands and put them directly into my enumeration! This works!! Thanks for all the input and your help! I am going to mark this question answered with your answer, as there probably is no way to do what I want to do in C++98. regards ;) btw I used the hash function described in this Thread, which works pretty well: http://stackoverflow.com/questions/7666509/hash-function-for-string – robo Dec 06 '15 at 01:38