Ho preso un esempio che ho trovato on-line in cui un constexpr del modulo _binary poteva essere valutato al momento della compilazione come unsigned long long e quindi ho provato a generalizzarlo per qualsiasi base da 2 a 36. Ad esempio, 17b1234_baseChange avrebbe essere valutato dalla base 17 come ((1 * 17 +2) * 17 + 3) * 17 + 4 = 5624.
Mi rendo conto che questo è un esempio forzato, ma mi chiedevo quali fossero i limiti per l'operatore "". Sembra il compilatore quando parser crea token separati per numeri e lettere. Ero curioso di sapere se si trattava di un bug o di un comportamento previsto. (Oltre a "b", ho provato altri separatori senza fortuna.) Grazie per la tua comprensione.
Riga di comando all'interno di link : g ++ - 4.9 -std = c ++ 14 -O3 -Wall -Wextra -pedantic -pthread -pedantic-errors main.cpp -lm & & ./a.out
Codice:
#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;
}