将字符串文字传递给模板字符数组参数
Passing a string literal to a template char array parameter
CTRE library 能够使用 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';
}
调用 to_int_runtime("0")
工作正常,但 to_int_compile_time<"0">()
抱怨不能将字符串文字用于此模板参数。 to_int_compile_time
应该怎么写才能把字符串字面量传入char数组模板参数?
能够做到这一点取决于 C++20 的一个鲜为人知的特性:非类型模板参数可以有一个 class 模板类型,没有指定模板参数。 CTAD 将确定这些论点。
因此,您创建了一个由 size_t N
模板化的 class,它具有 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] != '[=10=]')
expectedNullTerminatedArray();
std::copy_n(new_str, size, str);
}
};
然后执行 template <ConstString S> struct A {...};
,并使用 S.str
或 S.view()
检查字符串。
这里有一些额外的便利运算符 class:
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;
}
您还可以使用此 class:
模板 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);
CTRE library 能够使用 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';
}
调用 to_int_runtime("0")
工作正常,但 to_int_compile_time<"0">()
抱怨不能将字符串文字用于此模板参数。 to_int_compile_time
应该怎么写才能把字符串字面量传入char数组模板参数?
能够做到这一点取决于 C++20 的一个鲜为人知的特性:非类型模板参数可以有一个 class 模板类型,没有指定模板参数。 CTAD 将确定这些论点。
因此,您创建了一个由 size_t N
模板化的 class,它具有 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] != '[=10=]')
expectedNullTerminatedArray();
std::copy_n(new_str, size, str);
}
};
然后执行 template <ConstString S> struct A {...};
,并使用 S.str
或 S.view()
检查字符串。
这里有一些额外的便利运算符 class:
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;
}
您还可以使用此 class:
模板 UDLtemplate <ConstString S>
struct ConstStringParam {};
template <ConstString S>
[[nodiscard]] constexpr ConstStringParam<S> operator""_c()
{
return {};
}
// -----
template <ConstString S> void foo(ConstStringParam<S>) {}
foo("Sup!"_c);