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.
"Hello|World|"
or"Hello|World"
? The first case is easy by reusing your concat function, see here: godbolt.org/z/Gr3YYbr48 – Blowtorch...
in line 38 of the godbolt link. I don't think there are more parameters to expand? You create an expression ofs
and then expand this expression to every element of the pack. As an alternative to callingconcat
twice, you can just replace(s, "|")
in your attempt withconcat(s, "|").m_chars
: godbolt.org/z/P5qcxo5vr. BTW on an unrelated note: You can make all functionsconsteval
. – Blowtorch