Last active
November 22, 2018 14:41
-
-
Save mattbierner/5c698972de0cdd9de86a to your computer and use it in GitHub Desktop.
std::integral_constant user defined literal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
Defines a user defined literal that can create std::integral_constant values. | |
http://blog.mattbierner.com/stupid-template-tricks-stdintegral_constant-user-defined-literal/ | |
*/ | |
constexpr unsigned digit_to_value(char c) { | |
if (c >= 'a' && c <= 'f') return c - 'a' + 10; | |
else if (c >= 'A' && c <= 'F') return c - 'A' + 10; | |
else if (c >= '0' && c <= '9') return c - '0'; | |
else throw std::invalid_argument("c"); | |
} | |
template <typename sum, char... digits> | |
struct GetDigits { | |
using type = sum; | |
}; | |
template <unsigned... existing, char... xs> | |
struct GetDigits<std::integer_sequence<unsigned, existing...>, '\'', xs...> : | |
GetDigits< | |
std::integer_sequence<unsigned, existing...>, | |
xs...> { }; | |
template <unsigned... existing, char x, char... xs> | |
struct GetDigits<std::integer_sequence<unsigned, existing...>, x, xs...> : | |
GetDigits< | |
std::integer_sequence<unsigned, existing..., digit_to_value(x)>, | |
xs...> { }; | |
template <unsigned b, char... d> | |
struct BaseAndDigits { | |
static constexpr unsigned base = b; | |
using digits = typename GetDigits<std::integer_sequence<unsigned>, d...>::type; | |
}; | |
template <char... digits> | |
struct ParseNumber : BaseAndDigits<10, digits...> { }; | |
template <char... digits> | |
struct ParseNumber<'0', 'X', digits...> : BaseAndDigits<16, digits...> { }; | |
template <char... digits> | |
struct ParseNumber<'0', 'x', digits...> : BaseAndDigits<16, digits...> { }; | |
template <char... digits> | |
struct ParseNumber<'0', digits...> : BaseAndDigits<8, digits...> { }; | |
template <char... digits> | |
struct ParseNumber<'0', 'b', digits...> : BaseAndDigits<2, digits...> { }; | |
template <char... digits> | |
struct ParseNumber<'0', 'B', digits...> : BaseAndDigits<2, digits...> { }; | |
template <typename T, char... values> | |
struct ConstantFromString { | |
using number = ParseNumber<values...>; | |
template <unsigned x, unsigned... xs> | |
static constexpr unsigned long long fold(unsigned long sum, std::integer_sequence<unsigned, x, xs...>) { | |
return fold(x + number::base * sum, std::integer_sequence<unsigned, xs...>{}); | |
} | |
static constexpr unsigned long long fold(unsigned long sum, std::integer_sequence<unsigned>) { | |
return sum; | |
} | |
using type = std::integral_constant<T, static_cast<T>(fold(0, typename number::digits{}))>; | |
}; | |
template <int8_t x> | |
using byte = std::integral_constant<int8_t, x>; | |
template <char... digits> | |
constexpr auto operator ""_b() { | |
return typename ConstantFromString<typename byte<0>::value_type, digits...>::type{}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment