В общем есть реализация конвертации чисел в строки посредством константных выражений
/* IMPLEMENTATION */
/* calculate absolute value */
constexpr int abs_val (int x)
{ return x < 0 ? -x : x; }
/* calculate number of digits needed, including minus sign */
constexpr int num_digits (int x)
{ return x < 0 ? 1 + num_digits (-x) : x < 10 ? 1 : 1 + num_digits (x / 10); }
/* metaprogramming string type: each different string is a unique type */
template<char... args>
struct metastring {
const char data[sizeof... (args)] = {args...};
};
/* recursive number-printing template, general case (for three or more digits) */
template<int size, int x, char... args>
struct numeric_builder {
typedef typename numeric_builder<size - 1, x / 10, '0' + abs_val (x) % 10, args...>::type type;
};
/* special case for two digits; minus sign is handled here */
template<int x, char... args>
struct numeric_builder<2, x, args...> {
typedef metastring<x < 0 ? '-' : '0' + x / 10, '0' + abs_val (x) % 10, args...> type;
};
/* special case for one digit (positive numbers only) */
template<int x, char... args>
struct numeric_builder<1, x, args...> {
typedef metastring<'0' + x, args...> type;
};
/* convenience wrapper for numeric_builder */
template<int x>
class numeric_string
{
private:
/* generate a unique string type representing this number */
typedef typename numeric_builder<num_digits (x), x, '\0'>::type type;
/* declare a static string of that type (instantiated later at file scope) */
static constexpr type value {};
public:
/* returns a pointer to the instantiated string */
static constexpr const char * get ()
{ return value.data; }
};
/* instantiate numeric_string::value as needed for different numbers */
template<int x>
constexpr typename numeric_string<x>::type numeric_string<x>::value;
Есть реализация вычисления crc32 из строки
// Generate CRC lookup table
template <unsigned c, int k = 8>
struct f : f<((c & 1) ? 0xedb88320 : 0) ^ (c >> 1), k - 1> {};
template <unsigned c> struct f<c, 0>{enum {value = c};};
#define A(x) B(x) B(x + 128)
#define B(x) C(x) C(x + 64)
#define C(x) D(x) D(x + 32)
#define D(x) E(x) E(x + 16)
#define E(x) F(x) F(x + 8)
#define F(x) G(x) G(x + 4)
#define G(x) H(x) H(x + 2)
#define H(x) I(x) I(x + 1)
#define I(x) f<x>::value ,
constexpr unsigned crc_table[] = { A(0) };
// Constexpr implementation and helpers
constexpr uint32_t crc32_impl(const uint8_t* p, size_t len, uint32_t crc) {
return len ?
crc32_impl(p+1,len-1,(crc>>8)^crc_table[(crc&0xFF)^*p])
: crc;
}
constexpr uint32_t crc32(const uint8_t* data, size_t length) {
return ~crc32_impl(data, length, ~0);
}
constexpr size_t strlen_c(const char* str) {
return *str ? 1+strlen_c(str+1) : 0;
}
constexpr int WSID(const char* str) {
return crc32((uint8_t*)str, strlen_c(str));
}
При попытке использовать такую конструкций
numeric_string<WSID("TEST")>:: get();
Получаю ошибку компиляции вида
error: accessing value of 'TEST' through a ‘const uint8_t’ {aka ‘const unsigned char’} glvalue in a constant expression
Возможно ли как то совместить две эти реализации что бы получать на выходе crc32 в виде const char*?