I'm writing a hashing function to help speed up string comparisons.
My codebase compares strings against a lot of const char[]
constants, and it would be ideal if I could work with hashes instead. I went ahead and translated xxHash to modern C , and I have a working prototype that does work at compile time, but I'm not sure what the function definition should be for the main hashing function.
At the moment, I have this:
template <size_t arr_size>
constexpr uint64_t xxHash64(const char(data)[arr_size])
{...}
This does work, and I am able to do a compile time call like this
constexpr char myString[] = "foobar";
constexpr uint64_t hashedString = xxHash64<sizeof myString>(myString);
[Find a minimal example here]
All good so far, but I would like to add a user-defined literal wrapper function for some eye candy, and this is where the problem lies.
UDLs come with a fixed prototype, as specified here
The Microsoft doc stipulates "Also, any of these operators can be defined as constexpr".
But when I try to call my hashing function from a constexpr UDL:
constexpr uint64_t operator "" _hashed(const char *arr, size_t size) {
return xxHash64<size>(arr);
}
function "xxHash64" cannot be called with the given argument list
argument types are: (const char*)
And the error does make sense. My function expects a character array, and instead it gets a pointer.
But if I were to modify the definition of my xxHash64 function to take a const char *
, I can no longer work in a constexpr context because the compiler needs to resolve the pointer first, which happens at runtime.
So am I doing anything wrong here, or is this a limitation of UDLs or constexpr functions as a whole? Again, I'm not 100% sure the templated definition at the top is the way to go, but I'm not sure how else I could read characters from a string at compile time.
I'm not limited by any compiler version or library. If there is a better way to do this, feel free to suggest.
CodePudding user response:
there is no problem to call constexpr
function with constexpr
pointer as constant expression
constexpr uint64_t xxHash64(const char* s){return s[0];}
constexpr uint64_t operator "" _g(const char *arr,std::size_t){
return xxHash64(arr);
}
int main()
{
xxHash64("foo");
constexpr auto c = "foobar"_g;
return c;
}
would just work fine.
CodePudding user response:
with c 20, you can also get the size as constant expression with string literal operator template.
#include <cstdint>
template <std::size_t arr_size>
constexpr std::uint64_t xxHash64(const char(&data)[arr_size]){
return data[0];
}
template <std::size_t N>
struct hash_value{
std::uint64_t value;
constexpr hash_value(const char(&p)[N]):value(xxHash64(p)){}
};
template < hash_value v >
constexpr std::uint64_t operator ""_hashed() { return v.value; }
int main()
{
constexpr auto v = "foobar"_hashed;
return v;
}