I took an example I found on-line whereby a constexpr of the form _binary could be evaluated at compile time as an unsigned long long and then I tried to generalize it for any base from 2 to 36. For instance, 17b1234_baseChange would be evaluated from base 17 as ((1*17 +2)*17 + 3)*17 + 4 = 5624.
I realize this is kind of a contrived example but I was wondering what the limits are for operator"". Is seems like the compiler when parser is creating separate tokens for numbers and letters. I was curious if this was a bug or expected behavior. (In addition to 'b', I have tried other separators with no luck.) Thanks for your insight.
Command line within http://coliru.stacked-crooked.com/: g++-4.9 -std=c++14 -O3 -Wall -Wextra -pedantic -pthread -pedantic-errors main.cpp -lm && ./a.out
Code:
#include <iostream>
const char Delimiter = 'b';
typedef unsigned long long ULL;
/// Extract one "digit" from a digit string and then recurse.
template<unsigned short NumericBase, char Head, char... Rest>
struct baseChange_helper
{
constexpr ULL operator()(ULL result) const;
};
/// Teminate recursion when interpreting a numeric string.
template<unsigned short NumericBase, char Head> struct
baseChange_helper<NumericBase, Head>
{
constexpr ULL operator()(ULL result) const;
};
template<unsigned short NumericBase, char Head, char... Rest>
constexpr ULL baseChange_helper<NumericBase, Head, Rest...>::operator()
(ULL result) const
{
static_assert( (Head >= '0' && (Head <= '0' + std::min(NumericBase-1, 9)))
|| (NumericBase > 10 && (Head >= 'A' && Head <= 'A' +
std::min(NumericBase-10, 25)))
, "not a valid number in this base");
return baseChange_helper<Rest...>{}(result = result * (NumericBase -1)
+ ((Head > 'A') ? (10 + Head - 'A') : (Head - '0')));
}
template<unsigned short NumericBase, char Head>
constexpr ULL
baseChange_helper<NumericBase, Head>::operator()(ULL result) const
{
static_assert( (Head >= '0' && (Head <= '0' + std::min(NumericBase-1, 9)))
|| (NumericBase > 10 && (Head >= 'A' &&
Head <= 'A' + std::min(NumericBase-10, 25)))
, "not a valid number in this base");
return result * (NumericBase -1) +
((Head > 'A') ? (10 + Head - 'A') : (Head - '0'));
}
template<unsigned short NumericBase, char Head, char... Rest> struct
baseChange_parser
{
constexpr ULL operator()() const;
};
template<unsigned short NumericBase, char Head, char... Rest>
constexpr ULL baseChange_parser<NumericBase, Head, Rest...>::operator()()
const
{
static_assert( (Head == Delimiter && NumericBase > 1 && NumericBase < 36) ||
(Head >= '0' && Head <= '9'),
"not a valid base");
return ( Head == Delimiter ? baseChange_helper<NumericBase, Rest...>((ULL)0)
: baseChange_parser<NumericBase*10 + Head - '0', Rest...>()
);
}
template<char... Chars> constexpr ULL operator"" _baseChange()
{
return baseChange_parser<0, Chars...>{}();
}
int main() {
const ULL v = 17b1234_baseChange;
std::cout << v << std::endl;
}
_b14
. Or do you need it more dynamic? Because, to be honest, having "17b" in front of all your numbers doesn't look really readable to me.