Is there an alternative to having severals else if(...)'s?
Instead of a switch statement, you could write your own switch function.
Maybe it would look something like this:
#include <iostream>
#include <string>
#include <utility>
#include <tuple>
//pass in a bool as to whether or not we break
//make macro so it looks more like a switch statement
#define BREAK true
//template details used by outside functions
namespace switch_impl{
//represents a case statement
template <typename T, typename U>
struct Case_Statement{
U value;
T expression;
bool breaks;
Case_Statement(U value, T expression, bool breaks=false)
: value(value)
, expression(expression)
, breaks(breaks)
{}
};
//recursive template unpacking to evaluate in a fashion similar to switch statements
template<std::size_t I = 0, typename C, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
evaluate(C comparator, bool found, std::tuple<Tp...>& t)
{ }
template<std::size_t I = 0, typename C, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
evaluate(C comparator, bool found, std::tuple<Tp...>& t)
{
if (std::get<I>(t).value == comparator || found){
std::get<I>(t).expression();
if (!std::get<I>(t).breaks){
evaluate<I + 1, C, Tp...>(comparator,true,t);
}
}else{
evaluate<I + 1, C, Tp...>(comparator,false,t);
}
}
}
//base functions to compose so that it looks like a switch statement
template<typename T, typename... Statements>
void Switch(T comparator, Statements... statements)
{
auto t = std::make_tuple(statements...);
switch_impl::evaluate(comparator,false,t);
}
template<typename T, typename U>
auto Case(U value, T expression, bool breaks=false) -> switch_impl::Case_Statement<T,U>{
return switch_impl::Case_Statement<T,U>(value,expression,breaks);
}
//example usage
int main(){
//c style switch example:
switch (2){
case 1:
std::cout << "1\n";
break;
case 2:
std::cout << "2\n";
case 3:
std::cout << "3\n";
break;
case 4:
std::cout << "4\n";
break;
}
//c++ functional switch example:
Switch("2",
Case("1",[&](){
std::cout << "1\n";
},BREAK),
Case("2",[&](){
std::cout << "2\n";
}),
Case("3",[&](){
std::cout << "3\n";
},BREAK),
Case("4",[&](){
std::cout << "4\n";
},BREAK)
);
}
I've left out the default case, but you get the idea.
In fact, you might realize that this is slightly more powerful than constant expressions.
Welcome to the world of pattern matching,
which is a language feature, I think C++ could definitely use.