I wrote the following code for using string in compile time:
template<char... Chars>
struct CnstString {
template<char... Aped>
using push_back = CnstString<Chars..., Aped...>;
constexpr static char value[] = {Chars...};
};
It's fine when I use it like this:
#include <iostream>
using str = CnstString<'H', 'e', 'l', 'l', 'o', '\0'>;
int main()
{
std::cout << str << std::endl;
return 0; // it will output "Hello"
}
What I want to do is use a recursive template struct, splice a string given by the above code at compile time, and append a '\0'
to the array at the recursive end point.
The reason I wrote this code is because I want to concatenate a same string multiple times. Obviously I can't concatenate the same string together like "Hello""Hello"
.
The recursive template struct is shown below:
template<int N, typename Str>
struct RepeatStr {
using ret = RepeatStr<N-1, Str>; // this is an error, I don't know how to pass parameters
};
template<typename Str>
struct RepeatStr<-1, Str> {
using ret = Str:: template push_back<'\0'>;
};
However, I found that I didn't know how to append characters to itself using its characters in Str.
Is there something wrong? Or it's just impossible to do in compile time?
If possible, I would change definition of CnstString
to place '\0' only in value
template<char... Chars>
struct CnstString {
constexpr static char value[] = {Chars..., '\0'};
};
Then provide operator +
(which would allow Fold expression (C++17) later)
template <char... Cs1, char...Cs2>
CnstString<Cs1..., Cs2...> operator +(CnstString<Cs1...>, CnstString<Cs2...>) { return {}; }
Finally, you RepeatStr<N, Str>
which would have a type for Str{} + .. + Str{}
:
template<int N, typename Str>
struct RepeatStr {
// C++20
using ret = decltype([]<std::size_t... Is>(std::index_sequence<Is...>){
return ((static_cast<void>(Is), Str{}) + ...);
}(std::make_index_sequence<N>()));
};
As you are limited to C++14, replacing fold expression of C++17 by "recursive" function call:
template <typename T>
auto sum_impl(T t)
{
return t;
}
template <typename T, typename... Ts>
auto sum_impl(T t, Ts... ts)
{
return t + sum_impl(ts...);
}
And replace the template lambda(C++20) by regular template function:
template <typename Str, std::size_t... Is>
auto repeat_impl(std::index_sequence<Is...>)
{
return sum_impl((static_cast<void>(Is), Str{})...);
}
template<int N, typename Str>
struct RepeatStr {
using ret = decltype(repeat_impl<Str>(std::make_index_sequence<N>()));
};