Being able to do this hinges on a little-known feature of C++20: a non-type template parameter can have a class template type, without template arguments specified. CTAD will determine those arguments.
So you create a class templated by size_t N
, that has char[N]
as a member, is constructible from one, and N
is deducible by CTAD.
Example:
// 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]] constexpr 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);
}
};
Then you do template <ConstString S> struct A {...};
, and use either S.str
or S.view()
to examine the string.
And here are some extra convenience operators for this 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;
}
You can also have template UDLs with this class:
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);
ASSERT(new_str[N-1] == '\0');
withstatic_assert
, since that's where I'm trying to go with this, and the compiler does not considernew_str[N-1]
a valid constexpr expression. – Ecclesiolatry