Home > Net >  What is the proper definition for a constexpr function that take a character array?
What is the proper definition for a constexpr function that take a character array?

Time:11-19

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;
}
  • Related