Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to validate strings to compile time?

I am trying to make the following code work:

#include <string>
#include <tuple>
#include <print>

template<char Specifier>
struct ParseSpecifier;

template<>
struct ParseSpecifier<'s'>
{
    static void parse()
    {
        std::println("string");
    }
};

template<>
struct ParseSpecifier<'i'>
{
    static void parse()
    {
        std::println("integer");
    }
};

template<std::size_t Index>
void parse_format(const std::string_view format)
{
    if (Index == format.size())
        return;
    
    ParseSpecifier<format[Index]>::parse();
    parse_format<Index + 1>(format);
}

int main()
{
    parse_format<0>("iiisss");
}

I know there exist libraries (like fmt) that can compile time validate format strings so this must be possible somehow. I should note, the ultimate goal is not to print "string" and "integer", but rather to create a std::tuple based on the i and ss in the provided string. The string will always be known at compile time.

I am starting small as I am only just learning template metaprogramming. How can I make code like this work? I understand format is not constexpr as function parameters cannot be. Additionally, std::string_view cannot be a template parameter. If I use template<char... Chars> then I have to call the function like parse_format<0, 'i', 's', 's', 'i', 's'>();, which is horrible.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Is there any way I can get my attempted code to function? If not, what is the best strategy for compile time validation of strings?

Important note, the final function will be called with one compile time known parameter and one real time parameter (much like fmt::format).

Easy edit: https://godbolt.org/z/s8eoYarja

>Solution :

The way libfmt (and std::format) do it is by passing a custom class instead of std::string_view, with a consteval constructor accepting a string. Said constructor runs at compile-time and can e.g. throw (or do something else) to cause a compile-time error.

But this approach doesn’t let you do this:

create a std::tuple based on the i and ss in the provided string

This requires passing the string as a template parameter:

template <std::size_t N>
struct ConstString
{
    char value[N]{};

    constexpr ConstString() {}
    constexpr ConstString(const char (&str)[N])
    {
        std::copy_n(str, N, value);
    }

    [[nodiscard]] constexpr std::string_view view() const
    {
        return std::string_view(value, value + N - 1);
    }
};

template <ConstString S>
void foo();

int main()
{
    foo<"blah">();
}

Or with a slightly different call syntax:

template <ConstString>
struct ConstStringTag {};

template <ConstString S>
[[nodiscard]] ConstStringTag<S> constexpr operator""_c() {return {};}

template <ConstString S>
void foo(ConstStringTag<S>);

int main()
{
    foo("blah"_c);
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading