My suggestion is possible with C ++ 14, but with if constexpr and std::string_view this is not much to write.
First - we need a constexpr line - like this:
template <char... c> using ConstString = std::integer_sequence<char, c...>; template <char ...c> constexpr auto operator ""_cstr () { return ConstString<c...>{}; }
operator == also easier to write without a tuple pattern and with the fact that tuple now has constexpr operator == :
template <char... c1, char ...c2> constexpr bool operator == (ConstString<c1...>, ConstString<c2...>) { if constexpr (sizeof...(c1) == sizeof...(c2))
Next - determine the switch code:
template <typename Callable, typename Key> class StringSwitchCase; template <typename Callable, char ...c> struct StringSwitchCase<Callable, ConstString<c...>> { constexpr bool operator == (const std::string_view& str)
A default requirement is also required:
template <typename Callable> struct StringSwitchDefaultCase { constexpr bool operator == (const std::string_view&) { return true; } Callable call; }; template <typename Callable> constexpr auto makeStringSwitchDefaultCase(Callable call) { return StringSwitchDefaultCase<Callable>{call}; }
So StringSwitch is actually an if () {} else if () {} ... else {} construct:
template <typename ...Cases> class StringSwitch { public: StringSwitch(Cases&&... cases) : cases(std::forward<Cases>(cases)...) {} constexpr auto call(const std::string_view& str) { return call<0u>(str); } private: template <std::size_t idx> constexpr auto call(const std::string_view& str) { if constexpr (idx < sizeof...(Cases)) { if (std::get<idx>(cases) == str) { return std::get<idx>(cases).call(); } return call<idx + 1>(str); } else { return; } } std::tuple<Cases...> cases; };
And possible use:
StringSwitch cstrSwitch( makeStringSwitchCase(234_cstr, [] { cout << "234\n"; }), makeStringSwitchCase(ConstString<'a', 'b', 'c'>{}, // only C++ standard committee know why I cannot write "abc"_cstr [] { cout << "abc\n"; }), makeStringSwitchDefaultCase([] { cout << "Default\n"; })); cstrSwitch.call("abc"s);
We work a demo .
I manage to make ConstString much easier based on this post. Work demo2 .
The added part is as follows:
#include <boost/preprocessor/repetition/repeat.hpp> #include <boost/preprocessor/comma_if.hpp> #define ELEMENT_OR_NULL(z, n, text) BOOST_PP_COMMA_IF(n) (n < sizeof(text)) ? text[n] : 0 #define CONST_STRING(value) typename ExpandConstString<ConstString<BOOST_PP_REPEAT(20, ELEMENT_OR_NULL, #value)>, \ ConstString<>, sizeof(#value) - 1>::type template <typename S, typename R, int N> struct ExpandConstString; template <char S1, char ...S, char ...R, int N> struct ExpandConstString<ConstString<S1, S...>, ConstString<R...>, N> : ExpandConstString<ConstString<S...>, ConstString<R..., S1>, N - 1> {}; template <char S1, char ...S, char ...R> struct ExpandConstString<ConstString<S1, S...>, ConstString<R...>, 0> { using type = ConstString<R...>; };
By changing the first parameter ( 20 ) to BOOST_PP_REPEAT(20, ELEMENT_OR_NULL, #value) , we can control the maximum possible size of ConstString - and the use is as follows:
int main() { StringSwitch cstrSwitch( makeStringSwitchCase(CONST_STRING(234){}, [] { cout << "234\n"; }), makeStringSwitchCase(CONST_STRING(abc){}, [] { cout << "abc\n"; }), makeStringSwitchDefaultCase([] { cout << "Default\n"; })); cstrSwitch.call("abc"s); }