I want to design a compile-time-string class CTString
that can e.g. be constructed from a parameter pack of string literals. This works using a comma-fold-expression (for this toy example, I tried to avoid the use of any system headers to make it self-contained):
template<unsigned N>
struct CTString
{
char m_chars[N + 1U];
template<unsigned... Ns>
constexpr CTString(const char (&...s)[Ns])
{
auto* p{ m_chars };
((p = CopyN_(s, Ns - 1U, p)), ...);
*p = '\0';
}
// copy size characters and return one past last copy:
constexpr char* CopyN_(const char* pFrom, unsigned size, char* pTo)
{
for (auto i{ 0U }; i < size; ++i)
*(pTo++) = *(pFrom++);
return pTo;
}
};
template<unsigned... Ns>
constexpr auto concat(const char(&...s)[Ns])
{
return CTString<(0U + ... + (Ns - 1U))>{s...};
}
constexpr auto cHelloWorld{ concat("Hello", "World") };
static_assert(cHelloWorld.m_chars[9] == 'd');
static_assert(cHelloWorld.m_chars[10] == '\0');
Now I have an additional use case to insert a separator after each literal. How can I expand/fold the parameter pack to insert e.g. the literal "|"
after each element of the pack?
This is my feeble attempt that fails because the expression (s, "|")...
does not work: The comma here just leads to the left operand being discarded:
template<unsigned... Ns>
constexpr auto concatWithSeparator(const char(&...s)[Ns])
{
return CTString<(0U + ... + Ns)>{(s, "|")...};
}
// Compilation error:
constexpr auto cHelloCommaSeparated{ concatWithSeparator("Hello", "World") };
I can work around this problem by introducing a helper class and having the compile-time-string also accept packs of the helper class in its constructors. But I was wondering whether there is neat idiom that I am missing.(I did read and re-read this great article, but to no avail: C++20 idioms for parameter packs
The code that compiles is here: Godbolt Un-comment the last line to see how it fails.