Skip to content

Instantly share code, notes, and snippets.

@mattbierner
Last active November 22, 2018 14:41
Show Gist options
  • Save mattbierner/5c698972de0cdd9de86a to your computer and use it in GitHub Desktop.
Save mattbierner/5c698972de0cdd9de86a to your computer and use it in GitHub Desktop.
std::integral_constant user defined literal
/**
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