将字符串文字传递给模板字符数组参数

Bob*_*der 4 c++ string-literals compile-time constexpr c++20

CTRE库能够解析和使用类似语法在编译时验证的正则表达式ctre::match<"REGEX">(text_to_search)。我知道这种语法仅在 C++20 中受支持,这很好,但是无论我尝试什么,我都无法以这种方式使用字符串文字。这是一个非常简单的例子:

// The compiler refuses to pass string literals to STR in this compile time version.
template <char const STR[2]> constexpr int to_int_compile_time()
{
    return STR[0] - '0';
}

// It has no problems passing the string literal to str in this version.
int to_int_runtime(char const str[2])
{
    return str[0] - '0';
}
Run Code Online (Sandbox Code Playgroud)

调用to_int_runtime("0")工作正常,但to_int_compile_time<"0">()抱怨字符串文字不能用于此模板参数。应该如何to_int_compile_time编写才能将字符串文字传递到 char 数组模板参数中?

Hol*_*Cat 5

能够做到这一点取决于 C++20 的一个鲜为人知的特性:非类型模板参数可以具有类模板类型,而无需指定模板参数。CTAD 将确定这些论点。

因此,您创建了一个由 模板化的类size_t N,它char[N]作为一个成员,可以从一个构造,并且N可以由 CTAD 推导出。

例子:

// This does nothing, but causes an error when called from a `consteval` function.
inline void expectedNullTerminatedArray() {}

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

    static constexpr std::size_t size = N - 1;

    [[nodiscard]] std::string_view view() const
    {
        return {str, str + size};
    }

    consteval ConstString() {}
    consteval ConstString(const char (&new_str)[N])
    {
        if (new_str[N-1] != '\0')
            expectedNullTerminatedArray();
        std::copy_n(new_str, size, str);
    }
};
Run Code Online (Sandbox Code Playgroud)

然后您执行template <ConstString S> struct A {...};, 并使用S.strS.view()来检查字符串。

以下是此类的一些额外便利运算符:

template <std::size_t A, std::size_t B>
[[nodiscard]] constexpr ConstString<A + B - 1> operator+(const ConstString<A> &a, const ConstString<B> &b)
{
    ConstString<A + B - 1> ret;
    std::copy_n(a.str, a.size, ret.str);
    std::copy_n(b.str, b.size, ret.str + a.size);
    return ret;
}

template <std::size_t A, std::size_t B>
[[nodiscard]] constexpr ConstString<A + B - 1> operator+(const ConstString<A> &a, const char (&b)[B])
{
    return a + ConstString<B>(b);
}

template <std::size_t A, std::size_t B>
[[nodiscard]] constexpr ConstString<A + B - 1> operator+(const char (&a)[A], const ConstString<B> &b)
{
    return ConstString<A>(a) + b;
}
Run Code Online (Sandbox Code Playgroud)

您还可以使用此类拥有模板 UDL:

template <ConstString S>
struct ConstStringParam {};

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

// -----

template <ConstString S> void foo(ConstStringParam<S>) {}

foo("Sup!"_c);
Run Code Online (Sandbox Code Playgroud)