如何验证字符串编译时间?

问题描述 投票:0回答:1

我正在尝试使以下代码工作:

#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");
}

我知道存在可以编译时间验证格式字符串的库(如 fmt),因此这必须以某种方式实现。我应该注意,最终目标不是打印“字符串”和“整数”,而是根据提供的字符串中的

i
s
创建 std::tuple。该字符串在编译时始终是已知的。

我从小处开始,因为我刚刚学习模板元编程。我怎样才能使这样的代码工作?我知道格式不是 constexpr,因为函数参数不能是 constexpr。此外,std::string_view 不能是模板参数。如果我使用

template<char... Chars>
那么我必须调用像
parse_format<0, 'i', 's', 's', 'i', 's'>();
这样的函数,这太可怕了。

有什么方法可以让我尝试的代码正常运行吗?如果不是,字符串编译时验证的最佳策略是什么?

重要提示,最终函数将使用一个编译时已知参数和一个实时参数(很像 fmt::format)来调用。

轻松编辑:https://godbolt.org/z/s8eoYarja

c++ templates metaprogramming compile-time
1个回答
0
投票

libfmt(和

std::format
)的方式是传递自定义类而不是
std::string_view
,并使用接受字符串的
consteval
构造函数。所述构造函数在编译时运行并且可以例如抛出(或做其他事情)导致编译时错误。

但是这种方法不允许你这样做:

根据提供的字符串中的

std::tuple
i
创建
s

这需要将字符串作为模板参数传递:

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">();
}

或者使用稍微不同的调用语法:

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);
}
© www.soinside.com 2019 - 2024. All rights reserved.