I have written some code to cast const char*
to int
by using constexpr
and thus I can use a const char*
as a template argument. Here is the code:
#include <iostream>
class conststr
{
public:
template<std::size_t N>
constexpr conststr(const char(&STR)[N])
:string(STR), size(N-1)
{}
constexpr conststr(const char* STR, std::size_t N)
:string(STR), size(N)
{}
constexpr char operator[](std::size_t n)
{
return n < size ? string[n] : 0;
}
constexpr std::size_t get_size()
{
return size;
}
constexpr const char* get_string()
{
return string;
}
//This method is related with Fowler–Noll–Vo hash function
constexpr unsigned hash(int n=0, unsigned h=2166136261)
{
return n == size ? h : hash(n+1,(h * 16777619) ^ (string[n]));
}
private:
const char* string;
std::size_t size;
};
// output function that requires a compile-time constant, for testing
template<int N> struct OUT
{
OUT() { std::cout << N << '\n'; }
};
int constexpr operator "" _const(const char* str, size_t sz)
{
return conststr(str,sz).hash();
}
int main()
{
OUT<"A dummy string"_const> out;
OUT<"A very long template parameter as a const char*"_const> out2;
}
In this example code, type of out
is OUT<1494474505>
and type of out2
is OUT<106227495>
. Magic behind this code is conststr::hash()
it is a constexpr
recursion that uses FNV Hash function. And thus it creates an integral hash for const char* which is hopefully a unique one.
I have some questions about this method:
- Is this a safe approach to use? Or can this approach be an evil in a specific use?
- Can you write a better hash function that creates different integer for each string without being limited to a number of chars? (in my method, the length is long enough)
- Can you write a code that implicitly casts
const char*
toint constexpr
viaconststr
and thus we will not need aesthetically ugly (and also time consumer)_const
user-defined string literal? For exampleOUT<"String">
will be legal (and cast "String" to integer).
Any help will be appreciated, thanks a lot.