Reputation: 2110
I want to write a C++ utility which can do the following:
Current Workflow
int num;
std::string str;
switch(num){
case 2:
str = "two";
break;
case 5:
str = "five";
break;
case 7:
str = "seven";
break;
}
I want to achieve this:
//key is always guaranteed to be int but value can be anything
DECLARE_SWITCH( {
{2 , "two"},
{5 , "five"},
{7 , "seven"}
})
int num = 5;
std::string str;
match(num,str,ARR);
//here str == "five"
I want to write the DECLARE_SWITCH and match functions. There is no restriction on the language constructs - preprocessor MACRO, templates anything would do.However, it would be good if there is some simple solution or trick. I know about associative data structures but I do not want to use any data structure. This question is specifically about using switch case.
Upvotes: 2
Views: 584
Reputation: 16099
Hmm your looking for the X macro
WARNING CONCEPT CODE NOT TESTET
#define LIST_OF_VARIABLES \
X(2 , "two") \
X(5 , "five") \
X(7 , "seven")
template<class RetValue>
RetValue match(int key) {
#define SWITCH(CASE, VALUE) case CASE : return VALUE;
#define X(PAIR) SWITCH(PAIR)
// makes the actual switch case
switch(key) {
LIST_OF_VARIABLES
default: throw "fail";
}
#undef SWITCH
#undef X
}
int main()
int num = 5;
std::string str;
str = match<std::string>(num);
std::cout << str;
}
Upvotes: 0
Reputation: 6465
std::map
/ std::unordered_map
is ideal for this usecase.
Maps are associative containers that store elements formed by a combination of a key value and a mapped value, following a specific order.
In your case you need key to be an int
and mapped value std::string
.
Here is an example
std::map<int, std::string> t;
t[1] = "one";
t[2] = "two";
t[3] = "three";
std::cout << "Value for '2': " << t[2] << std::endl;
for (auto& it : t)
{
std::cout << it.first << ": " << it.second << std::endl;
}
for (auto& it : t)
{
if (it.second == "one")
{
std::cout << "Value mapped to 'one' is: " << it.first << std::endl;
}
}
Output
Value for '2': two
1: one
2: two
3: three
Value mapped to 'one' is: 1
In your case
std::map<int, std::string> DECLARE_SWITCH
{
{2 , "two"},
{5 , "five"},
{7 , "seven"}
};
int num = 2;
std::string str = DECLARE_SWITCH[num];
std::cout << str << '\n';
Upvotes: 3
Reputation: 2734
With the map you can even make the code look very similar to your original sample
#include <map>
#include <string>
#include <iostream>
int main()
{
std::map<int,std::string> DECLARE_SWITCH {
{2 , "two"},
{5 , "five"},
{7 , "seven"}
};
int num = 5;
std::string str = DECLARE_SWITCH[num];
std::cout << str << '\n';
return 0;
}
Note that operator [] will insert new entry to map if it is not present. To avoid such behavior you will have to use find
#include <map>
#include <string>
#include <iostream>
std::string match(int number, const std::map<int,std::string>& DECLARE_SWITCH )
{
auto q = DECLARE_SWITCH.find(number);
if (q==DECLARE_SWITCH.end()) {
return "";
}
else
return q->second;
}
int main()
{
const std::map<int,std::string> DECLARE_SWITCH {
{2 , "two"},
{5 , "five"},
{7 , "seven"}
}; //now we can declare map as const
int num = 5;
std::string str = match(num,DECLARE_SWITCH);
std::cout << str << '\n';
return 0;
}
Upvotes: 3