[英]Converting decimal to hexadecimal at compile time
我正在嘗試創建一個程序,該程序可以在編譯時從十進制數轉換為十六進制數。 不幸的是,我是元編程的新手,在編譯時我找不到一種方法。 有什么想法可以解決這個問題嗎?
如何在不違反模板元編程原理的情況下表示這樣的數字。
#include <algorithm> // std::reverse
#include <iterator> // std::begin, std::end
#include <iostream>
#include <tuple>
#include <type_traits> // std::integral_constant
namespace detail {
using std::tuple;
using std::tuple_cat;
using std::integral_constant;
template< unsigned x, int n_digits >
struct Hex_tuple_
{
using Type = decltype( tuple_cat(
typename Hex_tuple_< x & ((1 << 2*n_digits) - 1), n_digits/2 >::Type(),
typename Hex_tuple_< (x >> 2*n_digits), n_digits/2 >::Type()
) );
};
template< unsigned x >
struct Hex_tuple_< x, 1 >
{
using Type = tuple< integral_constant< int, x > >;
};
} // namespace detail
template< unsigned x >
using Hex_ = typename detail::Hex_tuple_< x, 2*sizeof( x ) >::Type;
template< int... digit >
auto operator<<(
std::ostream& stream,
const std::tuple< std::integral_constant< int, digit >... >&
)
-> std::ostream&
{
int digits[] = { digit... };
std::reverse( std::begin( digits ), std::end( digits ) );
for( int x : digits )
{
stream << "0123456789ABCDEF"[x];
}
return stream;
}
auto main() -> int
{
std::cout << Hex_<123456>() << "\n";
}
構建在編譯時表示給定無符號整數的基數B
的一般問題非常有趣。 可以通過應用構建編譯時std::array
的寶貴技術來簡潔地解決此問題 ,至少可以回溯到此答案
如下定義的函數模板digits
將返回一個以char
表示的編譯時以空值終止的std::array
,其中char
包含表示整數N
的基本Base
數字,對於在合理范圍[2,36]中的Base
(數字'0-9A-Z' )
#include <type_traits>
#include <array>
// Get the number of base `base` digits in `n`
constexpr std::size_t base_digits(unsigned long n, unsigned base)
{
return (n / base) == 0 ? 1 : 1 + base_digits(n / base,base);
}
// Convert the remainder `r` of division by some base to a based digit
constexpr char based_digit(unsigned r)
{
return r > 36 ? '!' : r < 10 ? '0' + r : 'A' + r - 10;
}
template <unsigned long N, unsigned Base,
std::size_t Len = base_digits(N,Base) + 1, unsigned ...Rems>
constexpr std::array<char, Len>
digits(std::enable_if_t<(Base > 1 && Base <= 36 && N < Base)> * = nullptr)
{
return std::array<char,Len>{{based_digit(N), Rems...,0}};
}
template <unsigned long N, unsigned Base,
std::size_t Len = base_digits(N,Base) + 1, unsigned ...Rems>
constexpr std::array<char,Len>
digits(std::enable_if_t<(Base > 1 && Base <= 36 && N >= Base)> * = nullptr)
{
return digits<N / Base, Base, Len, based_digit(N % Base), Rems...>();
}
在此測試之前添加:
constexpr auto decimal = digits<9876543210,10>();
constexpr auto hex = digits<9876543210,16>();
constexpr auto octal = digits<123456789,8>();
constexpr auto binary = digits<123456789,2>();
constexpr auto b_36 = digits<36 + 35,36>();
static_assert(decimal.size() == 11,"");
#include <iostream>
#include <cassert>
int main() {
char * pend;
assert(std::strtoul(decimal.data(),&pend,10) == 9876543210);
std::cout << decimal.data() << std::endl;
assert(std::strtoul(hex.data(),&pend,16) == 9876543210);
std::cout << hex.data() << std::endl;
assert(std::strtoul(octal.data(),&pend,8) == 123456789);
std::cout << octal.data() << std::endl;
assert(std::strtoul(binary.data(),&pend,2) == 123456789);
std::cout << binary.data() << std::endl;
assert(std::strtoul(b_36.data(),&pend,36) == 36 + 35);
std::cout << b_36.data() << std::endl;
return 0;
}
輸出為:
9876543210
24CB016EA
726746425
111010110111100110100010101
1Z
(gcc 4.9.2 / clang 3.5.1,-std = c ++ 14。適用於C ++ 11)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.