1

I'm trying to parse UUID expression using C++23, However compiling under clang 20.1.6 and gcc 15.1.0 find the operator as candidates yet it get ignored. here is my code:

union uuid_t {
    unsigned char e[16];
};

template <char... Cs>
constexpr uuid_t operator ""_uuid() {
    constexpr auto N = sizeof...(Cs);

    static_assert(N == 36,
        "UUID literal must be exactly 36 chars (8-4-4-4-12)");

    // build a null-terminated buffer
    constexpr char str[N + 1] = { Cs..., '\0' };

    // dash checks
    static_assert(str[8]  == '-' &&
                  str[13] == '-' &&
                  str[18] == '-' &&
                  str[23] == '-',
                  "Dashes must be at 8,13,18,23");

    // constexpr lambda to convert one hex char -> 0..15
    constexpr auto hex_val = [](const char c) {
        return static_cast<signed char>(
            (c >= '0' && c <= '9') ? (c - '0'):
            (c >= 'a' && c <= 'f') ? (10 + (c - 'a')):
            (c >= 'A' && c <= 'F') ? (10 + (c - 'A')):
             -1
        );
    };

    uuid_t result{};
    auto idx = 0;

    for (auto& byte : result.e)
    {
        // skip dash if present
        if constexpr(str[idx] == '-') ++idx;
        constexpr auto hi = hex_val(str[idx++]);

        if constexpr(str[idx] == '-') ++idx;
        constexpr auto lo = hex_val(str[idx++]);

        static_assert(hi != -1 && lo != -1,
          "Only 0-9,A-F or 0-9,a-f is allowed in uuid expression.");

        byte = static_cast<unsigned char>((hi << 4) | lo);
    }

    return result;
}


int main()
{
    constexpr auto g = "00112233-4455-6677-8899-AABBCCDDEEFF"_uuid;

    return 0;
}

using the operator uuid_t operator ""_uuid(const char* str, std::size_t) works correctly, However I want to use the template syntax and I have no clue why it is failing.

This is my try https://godbolt.org/z/PnWT6zY7o

Thanks.

2 Answers 2

7

This form of literal operator:

template <char... Cs>
constexpr uuid_t operator ""_uuid()

is only used for numeric literals.

It simply isn't selected for string literals.

For string literals, C++20 instead provides this form (example taken from cppreference):

template<std::size_t N>
struct DoubleString
{
    char p[N + N - 1]{};
 
    constexpr DoubleString(char const(&pp)[N])
    {
        std::ranges::copy(pp, p);
        std::ranges::copy(pp, p + N - 1);
    }
};
 
template<DoubleString A>
constexpr auto operator""_x2()
{
    return A.p;
}

Which means you can make your code work like this:

#include <cstddef>

union uuid_t {
    unsigned char e[16];
};

template <std::size_t N>
struct UuidBuf {
    static_assert(N == 37,  // buffer contains \0
                  "UUID literal must be exactly 36 chars (8-4-4-4-12)");

    uuid_t result{};

    constexpr UuidBuf(char const (&str)[N]) {
        // dash checks - can't use static_assert
        if (!(str[8] == '-' && str[13] == '-' && str[18] == '-' &&
              str[23] == '-'))
            throw "Dashes must be at 8,13,18,23";

        // constexpr lambda to convert one hex char -> 0..15
        constexpr auto hex_val = [](const char c) {
            return static_cast<signed char>(
            (c >= '0' && c <= '9') ? (c - '0'):
            (c >= 'a' && c <= 'f') ? (10 + (c - 'a')):
            (c >= 'A' && c <= 'F') ? (10 + (c - 'A')):
             throw "Only 0-9,A-F or 0-9,a-f is allowed in uuid expression."
        );
        };

        auto idx = 0;
        for (auto& byte : result.e) {
            // skip dash if present
            if (str[idx] == '-') ++idx;
            auto hi = hex_val(str[idx++]);

            if (str[idx] == '-') ++idx;
            auto lo = hex_val(str[idx++]);

            byte = static_cast<unsigned char>((hi << 4) | lo);
        }
    }
};

template <UuidBuf U>
constexpr uuid_t operator""_uuid() {
    return U.result;
}

int main() {
    constexpr auto g = "00112233-4455-6677-8899-AABBCCDDEEFF"_uuid;

    return 0;
}

https://godbolt.org/z/q7WPrPvTj

Sign up to request clarification or add additional context in comments.

4 Comments

The problem with this way is that I cannot use static_assert to check the content. but for me this is mostly a better way than using uuid_t operator ""_uuid(const char* str, std::size_t). Thanks
An exception thrown during compile time evaluation is also a compile error. Try it out on godbolt: change the UUID constants and check the error messages, they're pretty good.
Also, can you point me to the place in the standard where it says that this form for numeric literals.
12.6/5 defines the template forms of the literal operators. 5.13.8/5 defines the lookup rules for user-defined-string-literals. (/3 and /4 define the rules for integer and floating point literals).
0

Try this

consteval uuid_t parse_uuid(std::string_view str) {
    // same logic as your literal operator
    uuid_t result{};
    if (str.size() != 36) throw "UUID must be 36 chars";

    auto hex_val = [](char c) -> int {
        return (c >= '0' && c <= '9') ? (c - '0') :
               (c >= 'a' && c <= 'f') ? (10 + (c - 'a')) :
               (c >= 'A' && c <= 'F') ? (10 + (c - 'A')) : -1;
    };

    size_t j = 0;
    for (int i = 0; i < 16; ++i) {
        if (str[j] == '-') ++j;
        int hi = hex_val(str[j++]);
        if (str[j] == '-') ++j;
        int lo = hex_val(str[j++]);

        if (hi == -1 || lo == -1) throw "Invalid hex in UUID";
        result.e[i] = static_cast<unsigned char>((hi << 4) | lo);
    }

    return result;
}

constexpr uuid_t g = parse_u

2 Comments

Your code example is cut off.
Thank you for contributing to the Stack Overflow community. This may be a correct answer, but it’d be really useful to provide additional explanation of your code so developers can understand your reasoning. This is especially useful for new developers who aren’t as familiar with the syntax or struggling to understand the concepts. Would you kindly edit your answer to include additional details for the benefit of the community?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.